阅读790 返回首页    go 阿里云 go 技术社区[云栖]


单线程服务器


下面是单线程服务器代码:

01 package servers;
02  
03 import java.net.ServerSocket;
04 import java.net.Socket;
05 import java.io.IOException;
06 import java.io.InputStream;
07 import java.io.OutputStream;
08  
09 public class SingleThreadedServer implements Runnable{
10  
11     protected int          serverPort   = 8080;
12     protected ServerSocket serverSocket = null;
13     protected boolean      isStopped    = false;
14     protected Thread       runningThread= null;
15  
16     public SingleThreadedServer(int port){
17         this.serverPort = port;
18     }
19  
20     public void run(){
21         synchronized(this){
22             this.runningThread = Thread.currentThread();
23         }
24         openServerSocket();
25  
26         <strong>while(! isStopped()){
27             Socket clientSocket = null;
28             try {
29                 clientSocket = this.serverSocket.accept();
30             catch (IOException e) {
31                 if(isStopped()) {
32                     System.out.println("Server Stopped.") ;
33                     return;
34                 }
35                 throw new RuntimeException(
36                     "Error accepting client connection", e);
37             }
38             try {
39                 processClientRequest(clientSocket);
40             catch (IOException e) {
41                 //log exception and go on to next request.
42             }
43         }</strong>
44  
45         System.out.println("Server Stopped.");
46     }
47  
48     private void processClientRequest(Socket clientSocket)
49     throws IOException {
50         InputStream  input  = clientSocket.getInputStream();
51         OutputStream output = clientSocket.getOutputStream();
52         long time = System.currentTimeMillis();
53  
54         output.write(("HTTP/1.1 200 OK\n\n<html><body>" +
55                 "Singlethreaded Server: " +
56                 time +
57                 "</body></html>").getBytes());
58         output.close();
59         input.close();
60         System.out.println("Request processed: " + time);
61     }
62  
63     private synchronized boolean isStopped() {
64         return this.isStopped;
65     }
66  
67     public synchronized void stop(){
68         this.isStopped = true;
69         try {
70             this.serverSocket.close();
71         catch (IOException e) {
72             throw new RuntimeException("Error closing server", e);
73         }
74     }
75  
76     private void openServerSocket() {
77         try {
78             this.serverSocket = new ServerSocket(this.serverPort);
79         catch (IOException e) {
80             throw new RuntimeException("Cannot open port 8080", e);
81         }
82     }
83 }

下面是调用代码:

01 SingleThreadedServer server = new SingleThreadedServer(9000);
02 new Thread(server).start();
03  
04 try {
05     Thread.sleep(10 1000);
06 catch (InterruptedException e) {
07     e.printStackTrace();
08 }
09 System.out.println("Stopping Server");
10 server.stop();

当服务器启动后,你可以用一般的浏览器访问https://localhost:9000/

单线程服务器最核心的地方就是上面代码主循环里的黑体部分,我们再把它展示出来:

01 while(! isStopped()){
02      Socket clientSocket = null;
03      try {
04          clientSocket = this.serverSocket.accept();
05      catch (IOException e) {
06         if(isStopped()) {
07             System.out.println("Server Stopped.") ;
08             return;
09         }
10         throw new RuntimeException("Error accepting client connection", e);
11      }
12      try {
13          processClientRequest(clientSocket);
14      catch (IOException e) {
15          //log exception and go on to next request.
16      }
17  }

简短的说,服务器做了以下事情:

1 等待客户端请求
2 处理客户端请求
3 重复1,2

java服务器中的循环大多和这段循环很像,单线程服务器和多线程服务器的区别就在于单线程服务器处理客户端请求和Accept客户端连接使用的是同一个线程。而多线程服务器会把一个连接发给一个工作线程用来处理这个连接上的请求。

处理客户端连接上的请求和Accept客户端连接使用同一个线程不是一个好主意,客户端只有当服务器运行在serverSocket.accept()时,才能连接上服务器。服务器运行在serverSocket.accept()函数外的时间越长,客户端访问被拒绝的可能性就越大。这就是为什么多线程服务器将已建立连接的请求转发给工作线程的因。这样监听线程就能尽可能的运行在serverSocket.accept()之中。

转载自 并发编程网 - ifeve.com

最后更新:2017-05-19 10:25:47

  上一篇:go  《Spring Boot官方文档》18. 使用 @SpringBootApplication注解
  下一篇:go  KV存储的对比