關於java socket中的read方法阻塞問題
阿新 • • 發佈:2020-08-07
客戶端:
public class TCPClient { public static void main(String[] args) throws IOException { FileInputStream fis=new FileInputStream("E:\\Trump.jpg"); Socket socket=new Socket("127.0.0.1",8888); OutputStream os=socket.getOutputStream(); byte[] bytes=new byte[1024]; int len; while((len=fis.read(bytes))!=-1){ //將讀取到的資料傳輸到客戶端與伺服器端之間的IO流 os.write(bytes,0,len); } //讀伺服器回寫的資料 InputStream is=socket.getInputStream(); len=is.read(bytes); System.out.println(new String(bytes,0,len)); socket.close(); fis.close(); } }
伺服器端:
public class TCPServer { public static void main(String[] args) throws IOException { ServerSocket server=new ServerSocket(8888); Socket socket=server.accept(); InputStream is=socket.getInputStream(); FileOutputStream fos=new FileOutputStream("E:\\Test\\Trump.jpg"); int len; byte[] bytes=new byte[1024]; while ((len=is.read(bytes))!=-1) { fos.write(bytes,0,len); } OutputStream os=socket.getOutputStream(); os.write("檔案上傳完畢!".getBytes()); fos.close(); socket.close(); } }
這段程式碼執行以後會發現server類 read()方法發生了阻塞,經過查詢資料發現read()是一個阻塞函式(阻塞函式就是當這個函式不執行完,函式所線上程就一直停止在這裡不動。),如果客戶端沒有宣告斷開outputStream那麼它就會認為客戶端仍舊可能傳送資料,像read()這種阻塞讀取函式還有BufferedReader類種的 readLine()、DataInputStream種的readUTF()等。
解決方案:
Socket任意一端在呼叫完write()方法時呼叫shutdownOutput()方法關閉輸出流,這樣伺服器端的inputStream上的read操作就會返回-1, 這裡我們要注意下不能呼叫socket.getInputStream().close()。因為它會導致socket直接被關閉。 當然如果不需要繼續在socket上進行讀操作,也可以直接關閉socket。但是這個方法不能用於通訊雙方需要多次互動的情況。