1. 程式人生 > 實用技巧 >【Java】Java socket通訊使用read,readline函式的阻塞問題

【Java】Java socket通訊使用read,readline函式的阻塞問題

Socket通訊是Java網路程式設計中比較基礎的部分,其原理其實就是源ip,源埠和目的ip,目的埠組成的套接字通訊。其底層還設及到了TCP協議的通訊。

Java中的Socket通訊可以通過客戶端的Socket與服務端的ServerSocket通訊,同時利用IO流傳遞資料,也就是說Socket通訊是面向流的使用的是BIO,並不同於後來的NIO通訊面向緩衝。Socket通訊中使用的IO流的read,readline等函式都是阻塞的,這就導致了在通訊過程中,雙方不能確定什麼時侯是流的結束,針對這種可以通過約定結束符的方式進行結束,也可以約定一次傳輸的位元組流的長度。下面通過程式碼進行說明

客戶端

建立客戶端執行緒,在run方法中不斷對服務端進行傳送訊息,模擬多個客戶端的通訊,通過寫入換行符,表明這次通訊的結束。

 1 class Client implements Runnable {
 2 
 3     private byte[] targetIp;
 4     private int port;
 5 
 6     Client(byte[] ip, int port) {
 7         this.targetIp = ip;
 8         this.port = port;
 9     }
10 
11     @Override
12     public void run() {
13         try {
14             InetAddress inetAddress = InetAddress.getByAddress(targetIp);
15 Socket socket = new Socket(inetAddress, port); 16 System.out.println("client"); 17 BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream())); 18 BufferedWriter socketOutput = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
19 20 int i = 0; 21 String NAME = "Client"; 22 while (true) { 23 socketOutput.write("This msg from " + NAME + " msg id is " + i); 24 socketOutput.write("\n");//約定結束符表示流的結束 25 i++; 26 socketOutput.flush(); 27 System.out.println("here"); 28 String str = null; 29 if (!(str = socketInput.readLine()).equals("\n")) { 30 System.out.println(str); 31 } 32 33 } 34 35 /*socket.shutdownInput(); 36 socket.shutdownOutput();*/ 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 41 } 42 }

服務端

服務端通過accept接受客戶端的連線,這個操作是阻塞的,直到有客戶端的連線才能進行下一步。

 1 class Server implements Runnable {
 2 
 3     private int port;
 4 
 5     Server(int port) {
 6         this.port = port;
 7     }
 8     @Override
 9     public void run() {
10         try {
11             ServerSocket serverSocket = new ServerSocket(port);
12 
13             InetAddress inetAddress = serverSocket.getInetAddress();
14             System.out.println("server" + inetAddress.getHostAddress());
15             Socket socket = serverSocket.accept();
16             BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
17             BufferedWriter socketOutput = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
18 
19             int i = 0;
20             while (true) {
21                 String str = null;
22                 if (!(str = socketInput.readLine()).equals("\n")) System.out.println(str);
23                 System.out.println("server");
24 
25                 String NAME = "Server";
26                 socketOutput.write("This msg from " + NAME + " msg num is " + i + " reply to " + str);
27                 socketOutput.write("\n");
28                 i++;
29                 socketOutput.flush();
30             }
31 
32 //            socket.shutdownInput();
33 //            socket.shutdownOutput();
34         } catch (IOException e) {
35             e.printStackTrace();
36         }
37 
38     }
39 }

測試

 1 public class SocketTest {
 2     public static void main(String[] args) {
 3         byte[] ip = {127, 0, 0, 1};
 4         int port = 27149;
 5         Thread server = new Thread(new Server(port), "server");
 6         server.start();
 7         Thread client = new Thread(new Client(new byte[]{0,0,0,0}, 27149));
 8         client.start();
 9     }
10 }

結果

服務端針對客戶端的每條資訊都能夠進行讀取並返回訊息給客戶端,但是如果註釋掉寫入換行符,並判斷讀取是否是換行符的程式碼,就無法讀取到流的結束。