閱讀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存儲的對比