首页 > 代码库 > NIO2 (1) --- TCP (blocking)

NIO2 (1) --- TCP (blocking)

這一篇要說明的是,如何使用 JDK 7 推出的 NIO 2 進行 TCP 程式開發,底下的類別圖只是其中較重要的部份,要詳細了解各類別關係,及各類別的 method,請查閱 API Documents。

 NIO 2 同時提供 blocking 和 non-blocking 的模式,blocking 模式的程式因為會在接收資料時程式暫停,直到完整收完資料才又繼續執行,程式邏輯會是循序的; non-blocking 模式並不會停在接收資料的那一行程式上,而是繼續執行,至於資料傳入時,通常就由另一個執行緒接收並處理,所以,non-blocking 程式會寫成多執行緒,邏輯也會複雜許多,好處是效率會比較好。底下先來看一下個 blocking 程式,很簡單的一個 echo sever。

 1 package idv.steven.nio2;
 2 
 3 import java.io.IOException;
 4 import java.net.InetSocketAddress;
 5 import java.net.StandardSocketOptions;
 6 import java.nio.ByteBuffer;
 7 import java.nio.channels.ServerSocketChannel;
 8 import java.nio.channels.SocketChannel;
 9 
10 public class EchoServer {
11 
12     public static void main(String[] args) {
13         final int DEFAULT_PORT = 5555;
14         final String IP = "127.0.0.1";
15         ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
16         
17         //create a new server socket channel
18         try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
19             //continue if it was successfully created
20             if (serverSocketChannel.isOpen()) {
21                 //set the blocking mode
22                 serverSocketChannel.configureBlocking(true);
23                 //set some options
24                 serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
25                 serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
26                 //bind the server socket channel to local address
27                 serverSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT));
28                 //display a waiting message while ... waiting clients
29                 System.out.println("Waiting for connections ...");
30                 //wait for incoming connections
31                 while(true){
32                     try (SocketChannel socketChannel = serverSocketChannel.accept()) {
33                         System.out.println("Incoming connection from: " +
34                         socketChannel.getRemoteAddress());
35                         //transmitting data
36                         while (socketChannel.read(buffer) != -1) {
37                             buffer.flip();
38                             socketChannel.write(buffer);
39                             if (buffer.hasRemaining()) {
40                                 buffer.compact();
41                             } else {
42                                 buffer.clear();
43                             }
44                         }
45                     } 
46                     catch (IOException ex) {
47                         
48                     }
49                 }
50             } else {
51                 System.out.println("The server socket channel cannot be opened!");
52             }
53         } 
54         catch (IOException ex) {
55             System.err.println(ex);
56         }
57     }
58 }

現在來解釋一下上面的程式:

  • Line 15: allocate 一塊記憶體,作為接收資料之用。
  • Line 18: 開啟一個 channel 作為接收資料之用,但此時尚未真正將服務 bind 到指定的 IP 和 port 上。
  • Line 20: 檢查是否確實開啟成功。
  • Line 22: 設定這個 TCP 服務為 blocking 模式。
  • Line 25: 這個設定在 multicast 才有用,在 TCP 其實可以不用設定。
  • Line 27: 到這裡,服務才真的 bind 到網路上。
  • Line 32: 程式會停在這,等待 request 進來。
  • Line 36~44: 將收到的資料放到 buffer。