接下來看程式及說明:
- client
1 package idv.steven.sync; 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.CharBuffer; 8 import java.nio.channels.SocketChannel; 9 import java.nio.charset.Charset; 10 import java.nio.charset.CharsetDecoder; 11 import java.util.Random; 12 13 public class Client { 14 15 public static void main(String[] args) { 16 final int DEFAULT_PORT = 5555; 17 final String IP = "127.0.0.1"; 18 19 ByteBuffer rcvBuffer = ByteBuffer.allocateDirect(1024); 20 Charset charset = Charset.forName("UTF-8"); // 網路傳輸時以 UTF-8 編碼 21 CharsetDecoder decoder = charset.newDecoder(); 22 23 // 建立 socket channel,在 NIO 2 裡,讀寫由 stream 改為 channel。 24 try (SocketChannel socketChannel = SocketChannel.open()) { 25 // 確認開啟 channel 成功 26 if (socketChannel.isOpen()) { 27 // NIO 2 為 TCP 網路程式提供 blocking 和 non-blocking 兩種模式 28 socketChannel.configureBlocking(true); 29 // 設定 socket 的一些參數 30 socketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 128 * 1024); 31 socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 128 * 1024); 32 // 要求 JVM 保持 socket 連線,不過,要如何保持和 OS 有關,還是得 OS 決定。 33 socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); 34 // 當 channel close 時,還有未送出的資料,要等待幾秒? 時間到仍強制關閉! 35 socketChannel.setOption(StandardSocketOptions.SO_LINGER, 5); 36 37 // 連線到 server socket 38 socketChannel.connect(new InetSocketAddress(IP, DEFAULT_PORT)); 39 40 // 確認連線是否成功 41 if (socketChannel.isConnected()) { 42 Random random = new Random(); 43 ByteBuffer sendBuffer = ByteBuffer.wrap(String.valueOf(random.nextInt(100)).getBytes()); 44 socketChannel.write(sendBuffer); 45 // socket 讀資料,不一定一次就可以完全讀完對方送來的資料,要讀到沒資料為止。 46 while (socketChannel.read(rcvBuffer) != -1) { 47 System.out.println("continue ..."); 48 } 49 rcvBuffer.flip(); 50 CharBuffer charBuffer = decoder.decode(rcvBuffer); 51 System.out.println(charBuffer); 52 } else { 53 System.out.println("連線失敗!"); 54 } 55 } else { 56 System.out.println("socket channel 開啟失敗!"); 57 } 58 } catch (IOException ex) { 59 System.err.println(ex); 60 } 61 } 62 }
- server
1 package idv.steven.sync; 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.CharBuffer; 8 import java.nio.channels.ServerSocketChannel; 9 import java.nio.channels.SocketChannel; 10 import java.nio.charset.Charset; 11 import java.nio.charset.CharsetDecoder; 12 import java.nio.charset.CharsetEncoder; 13 14 public class EchoServer { 15 16 public static void main(String[] args) { 17 final int DEFAULT_PORT = 5555; 18 final String IP = "127.0.0.1"; 19 ByteBuffer buffer = ByteBuffer.allocateDirect(1024); 20 Charset charset = Charset.forName("UTF-8"); // 網路傳輸時以 UTF-8 編碼 21 CharsetEncoder encoder = charset.newEncoder(); 22 CharsetDecoder decoder = charset.newDecoder(); 23 24 // 建立一個 server socket channel 25 try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) { 26 // 確認 server socket channel 開啟成功 27 if (serverSocketChannel.isOpen()) { 28 // 設定 TCP 傳輸方式為 blocking 模式 29 serverSocketChannel.configureBlocking(true); 30 // 設定 channel 的一些參數 31 serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024); 32 serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); 33 // 繫結 server socket 到指定的 IP 和 port 34 serverSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT)); 35 36 while(true){ 37 System.out.println("等待連線 ..."); 38 try (SocketChannel socketChannel = serverSocketChannel.accept()) { 39 System.out.println("連線來至: " + socketChannel.getRemoteAddress()); 40 while (socketChannel.read(buffer) <= 0) { 41 System.out.println("continue ..."); 42 } 43 44 buffer.flip(); 45 CharBuffer charBuffer = CharBuffer.wrap("回傳: " + decoder.decode(buffer)); 46 ByteBuffer response = encoder.encode(charBuffer); 47 socketChannel.write(response); 48 buffer.clear(); 49 } 50 catch (IOException ex) { 51 ex.printStackTrace(); 52 } 53 } 54 } else { 55 System.out.println("server socket channel 開啟失數!"); 56 } 57 } 58 catch (IOException ex) { 59 System.err.println(ex); 60 } 61 } 62 }上面的程式,client 和 server 間傳遞的訊息(電文)就只有個數字,一般來說,TCP 程式的電文不會這麼簡單,大部份會有 header 和 body,在電文最前面也會有個特殊字元當作起始,電文最後還會有特殊字元當作結尾。在台灣證券交易所的網站,就有台股相關的電文規格書,是個很好的參考,進到網站後,選擇上方選單「市場公告 > 公文查詢」,找到「資訊傳輸作業手冊」就有完整的規格。
沒有留言:
張貼留言