1. 程式人生 > >Socket程式設計 之 一種死鎖現象

Socket程式設計 之 一種死鎖現象

剛接觸socket程式設計的過程中,很容易出現死鎖的現象。下面我來介紹一種死鎖的原因和解決的方法。

先來看這段程式碼:

/*客戶端傳送一個資訊到服務端*/
 Socket socket = new Socket("127.0.0.1", 8081);
 outputStream = socket.getOutputStream();
 outputStream.write("伺服器我想要一個html檔案".getBytes());

/*接受伺服器傳來的響應資訊*/
 inputStreams = socket.getInputStream();
 byte[] bytes = new byte
[1024]; StringBuilder stringBuilder = new StringBuilder(); int len = 0; while((len = inputStreams.read(bytes))!=-1){ stringBuilder.append(new String(bytes,0,len)); }

程式碼很簡單。就是先往伺服器傳送一個資訊,然後伺服器解析完資訊後,傳回一個響應的內容。然後客戶端再接受該響應。

再來看伺服器端的程式碼:

 ServerSocket serverSocket = new ServerSocket(8081, 1, InetAddress.getByName("127.0.0.1"
)); /*接受客戶端的socket,若沒有連線,會一直阻塞到有連線進來*/ Socket socket = serverSocket.accept(); /*伺服器解析客戶端傳來的資訊*/ inputStream = socket.getInputStream(); StringBuilder sb = new StringBuilder(); byte[] bytes = new byte[1024]; int len = 0; while((len=inputStream.read(bytes))!=-1){ sb.append(new String(bytes,0,len)); } /*伺服器解析完傳來的資訊後,做出響應*/
outputStream = socket.getOutputStream(); outputStream.write("html檔案來了".getBytes());

1.假設伺服器的執行緒先與客戶端執行。ServerSocket被執行到,然後呼叫accept();處於阻塞,一直等到一個socket進來。

2.與此同時客戶端生成了一個socket並且傳來了一個資訊“伺服器我想要一個html檔案”。writer被執行後會繼續執行到inputStreams.read(),因為read是阻塞的會一直等到服務端把響應資訊傳回。所以出於阻塞中。

3.accept()接受到socket之後就會去解析客戶端傳來的資訊了,執行到inputStream.read()的時候,也會被阻塞。有人問客戶端不是傳來了“伺服器我想要一個html檔案”的資訊了嗎?為什麼read還會被阻塞啊。這是因為read還沒有讀到-1。

伺服器沒有讀到-1,會以為還有資訊要傳來,於是也處於等到中。可是客戶端已經傳輸好了,並且在等伺服器給響應資訊呢。於是就發生了死鎖。

解決的辦法有兩種:

第一種方法close流,相當於給流中加入一個結束標記-1
第二種方法:s.shutdownOutput();//關閉客戶端的輸出流。

相當於給流中加入一個結束標記-1.這個樣子伺服器的輸入流的reaLine方法就會讀到一個-1,然後結束readLIne方法。也可以這樣理解s.shutdownOutput();關閉的是客戶端的輸出流,同時伺服器端的輸入流也隨之關閉。s.shutdownIntput();也是同樣的道理,關閉客戶端的輸入流,同時伺服器端的輸出流也隨之關閉。

通過socket.shutdownOutput()關閉輸出流,但socket仍然是連線狀態,連線並未關閉
如果直接關閉輸入或者輸出流,即:in.close()或者out.close(),會直接關閉socket