關於建立一個TCP服務端出現阻塞問題
這裡是tcp客戶端的程式碼
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Socket_client {
public static void main(String[] args) throws UnknownHostException, IOException { //first,建立一個socket物件 Socket s = new Socket("192.168.1.107",20000); //second,獲取Socket中的輸出流 OutputStream out = s.getOutputStream(); //third,傳送資訊 out.write("嘿嘿嘿".getBytes()); //新增讀取伺服器返回資訊功能 //使用socket流讀取伺服器返回資料 InputStream in = s.getInputStream(); byte[] b = new byte[1024]; int len = in.read(b); String str = new String(b,0,len); System.out.println(str); //關閉資源 s.close(); }
}
這裡是tcp服務端的程式碼
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server_Socket {
public static void main(String[] agrs) throws IOException{
//先建立一個服務Socket
ServerSocket ss = new ServerSocket(20000);
//獲取客戶Socket物件 Socket s = ss.accept(); //使用客戶的Socket物件將資訊打印出來 InputStream in = s.getInputStream(); byte[] b = new byte[1024]; int len; while((len = in.read(b))!=-1){ //問題就出在這裡,用迴圈讀取,讀取-1時,出現阻塞,後面程式碼無法執行 String str = new String(b,0,len); System.out.println(str); } //使用客戶的Socket物件將成功接受資訊的資訊反饋給客戶端 OutputStream out = s.getOutputStream(); out.write("成功接受到資訊".getBytes()); //關閉資源 s.close(); ss.close(); }
}
先執行了服務端,然後再執行客戶端,服務端收到客戶端發來的string後阻塞了,客戶端也阻塞了,無法接受服務端回覆的string
如果我把服務端循壞程式碼改成如下:
//使用客戶的Socket物件將資訊打印出來
InputStream in = s.getInputStream();
byte[] b = new byte[1024];
int len = in.read(b);
String str = new String(b,0,len);
System.out.println(str);
--------------------------------------------------
程式能正常執行,為何?
這個問題本人已經解決了,一直沒時間,現在寫一下。為什麼 while((len=in.read(b))!=-1) 會阻塞呢?這是因為read()在讀的時候沒有讀到結束符,
也就是說從socket的輸入流中沒有獲取到結束標記,所以一直在等待著客戶端繼續傳送位元組,然而客戶端已經發送完畢,進行到 “使用socket流讀取伺服器返回資料”
這一步,這時,客戶端這邊的read()開始等待服務端返回的位元組,因此,兩邊就陷入互相等待的狀況!!!
解決辦法:在客戶端
//third,傳送資訊
out.write("嘿嘿嘿".getBytes());
//在這一步後面,再加一句作用是加入socket流的結束標誌,但並不是關閉流資源,告訴服務端,資料傳送完畢,讓伺服器停止讀取
s.shutdownOutput();
PS:其實shutdownOutput()這個方法相當於服務端的while((len=in.read())!=null){..........省略; 加入 if(in.read()=="end"){break}},當接受到結束標記“end”的時候就
跳出迴圈了,或者理解為傳入了一個null,就跳出迴圈。