Java中的单线程服务器
时间:2020-01-09 10:36:12 来源:igfitidea点击:
本文将展示如何在Java中实现单线程服务器。单线程服务器不是服务器的最佳设计,但是代码很好地说明了服务器的生命周期。多线程服务器上的以下文本将基于此代码模板。
这是一个简单的单线程服务器:
package servers; import java.net.ServerSocket; import java.net.Socket; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class SingleThreadedServer implements Runnable{ protected int serverPort = 8080; protected ServerSocket serverSocket = null; protected boolean isStopped = false; protected Thread runningThread= null; public SingleThreadedServer(int port){ this.serverPort = port; } public void run(){ synchronized(this){ this.runningThread = Thread.currentThread(); } openServerSocket(); while(! isStopped()){ Socket clientSocket = null; try { clientSocket = this.serverSocket.accept(); } catch (IOException e) { if(isStopped()) { System.out.println("Server Stopped.") ; return; } throw new RuntimeException( "Error accepting client connection", e); } try { processClientRequest(clientSocket); } catch (Exception e) { //log exception and go on to next request. } } System.out.println("Server Stopped."); } private void processClientRequest(Socket clientSocket) throws Exception { InputStream input = clientSocket.getInputStream(); OutputStream output = clientSocket.getOutputStream(); long time = System.currentTimeMillis(); byte[] responseDocument = "<html><body>" + "Singlethreaded Server: " + time + "</body></html>".getBytes("UTF-8"); byte[] responseHeader = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Content-Length: " + responseDocument.length + "\r\n\r\n".getBytes("UTF-8"); output.write(responseHeader); output.write(responseDocument); output.close(); input.close(); System.out.println("Request processed: " + time); } private synchronized boolean isStopped() { return this.isStopped; } public synchronized void stop(){ this.isStopped = true; try { this.serverSocket.close(); } catch (IOException e) { throw new RuntimeException("Error closing server", e); } } private void openServerSocket() { try { this.serverSocket = new ServerSocket(this.serverPort); } catch (IOException e) { throw new RuntimeException("Cannot open port 8080", e); } } }
这是运行它的代码:
SingleThreadedServer server = new SingleThreadedServer(9000); new Thread(server).start(); try { Thread.sleep(10 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Stopping Server"); server.stop();
服务器运行时,我们可以使用普通的Web浏览器访问它。使用地址http:// localhost:9000 /
服务器循环
单线程服务器最有趣的部分是其主循环,在上面的代码中以粗体显示。循环在这里重复:
while(! isStopped()){ Socket clientSocket = null; try { clientSocket = this.serverSocket.accept(); } catch (IOException e) { if(isStopped()) { System.out.println("Server Stopped.") ; return; } throw new RuntimeException("Error accepting client connection", e); } try { processClientRequest(clientSocket); } catch (IOException e) { //log exception and go on to next request. } }
简而言之,服务器要做的是:
- 等待客户要求
- 处理客户要求
- 从1开始重复。
对于大多数用Java实现的服务器,此循环几乎相同。单线程服务器与多线程服务器的区别在于,单线程服务器在接受客户端连接的同一线程中处理传入的请求。多线程服务器将连接传递给处理请求的工作线程。
在接受客户端连接的同一线程中处理传入请求不是一个好主意。服务器只能在serverSocket.accept()方法调用内时,客户端才能连接到服务器。侦听线程在" serverSocket.accept()"调用之外花费的时间越长,客户端被拒绝访问服务器的可能性就越高。这就是多线程服务器将传入的连接传递到工作线程的原因,工作线程将处理请求。这样,侦听线程在serverSocket.accept()
调用之外花费的时间尽可能少。