记录一次Socket的异常:InputStream.read()阻塞问题
起先是在Socket編程時,服務端取得客戶端發送的數據,但是在InputStream.read()的時候,一直停在那,然后取了解了read方法才知道阻塞問題
代碼示例:
//端口數據取得 byte[] b = new byte[1024]; in.read(b);//阻塞地方 String contents = new String(b).trim();//trim去除多余空格,否則,讀進來的是byte[1024]個占位字節Logger.getLogger(Constant.TASK).info("端口數據取得:" + contents);JAVA里的IO 目前有兩種,一種是早期發布的I/O模型,也就是所謂的BIO(Blocking I/O);另一種是JDK1.4里發布的基于 多路復用實現的NIO。
?
阻塞型 I/O,主要阻塞在兩個地方:
第一:在調用InutStream.read 方法是阻塞的,它會一直等到數據到來時(或超時)才會返回;第二:在調用ServerSocket.accept()方法時,也會一直阻塞到有客戶端連接才會返回;
?
目前大部分的客戶端服務端的網絡應用軟件的早期版本的I/O都是使用阻塞型的I/O實現。
阻塞型的I/O 存在以下幾點問題:
首先,InputStream.read()方法在其緩存區未滿時,會造成阻塞,只有一定的數據填滿了緩存區或者客戶端關閉了套接字,方法才會返回。
其次,會產生大量的垃圾,BufferedReader創建了緩存區來從套接字中讀入數據,但是同樣創建了一些字符串存儲這些數據。這些String很快變成垃圾需要回收。
類似的,讀寫操作被阻塞而且向流中一次寫入一個字符會造成效率低下,所以應該使用緩存區,但一旦使用緩存,流又會產生更多是垃圾。
另外,通常在JAVA中處理阻塞I/O要用到線程(大量的線程),一般是實現一個線程池來處理請求。線程使得服務器可以處理多個連接,但是他們同樣也引發了許多問題。每個線程擁有
自己的??臻g并且占用一些CPU時間,耗費很大,而且很多時間是浪費了阻塞I/O操作上,沒有有效利用CPU.次接收的操作是否結束了.???
可以看一下源碼
public abstract class InputStream extends Object implements Closeable此抽象類是表示字節輸入流的所有類的超類。
需要定義?InputStream?的子類的應用程序必須始終提供返回下一個輸入字節的方法。
個人理解,這種對象的概念有點像需要數據傳輸雙方之間的一個通道,這個通道負責接收數據(與之對應還有OutPutStream 負責發送數據)。
InputStream 中的read方法用于讀取數據,方法有3個重載。
read()從輸入流讀取下一個數據字節。 read(byte[] b)從輸入流中讀取一定數量的字節并將其存儲在緩沖區數組 b 中。 read(byte[] b, int off, int len)將輸入流中最多 len 個數據字節讀入字節數組。其中InputStream.read()方法,這個方法是從流里每次只讀取讀取一個字節,效率會非常低。????
更好的方法是用InputStream.read(byte[] b)或者InputStream.read(byte[] b,int off,int len)方法,一次讀取多個字節。
這里有一點需要特別注意:read?方法在輸入數據可用、檢測到文件末尾或者拋出異常前,此方法一直阻塞。
Socket流這里還存在另外一個問題,socket流和文件流不太一樣,文件流很容易知道文件末尾,到了文件末尾,直接就把流close掉就OK了。但是socket 流不一樣,你無法知道它什么時候到末尾,所以連接一直保持著,流也一直保持阻塞狀態。即使用了帶參數的read方法,返回了有效數據,但其實流仍然沒有關閉,處于阻塞狀態。
針對這種請情況,一般就需要通信的雙方約定數據傳輸的協議了。
①比如,約定消息的頭部首先明確此次傳輸數據的大小。這樣服務端就可以有目的性的讀取數據
如果采用一個一個字節讀取的話,就需要先兩方約定好。不然就會造成read一直在阻塞狀態。
②采用InputStrea.shutdownOutput(),在客戶端的關閉Stream輸出,這樣服務端就不會一直在等待輸入流的輸入
這時候可以采用一次性讀取的read(b[])方法,注意的是b[]要不小于傳輸過來的數據大小,不然只會讀取其中一部分。
總結
以上是生活随笔為你收集整理的记录一次Socket的异常:InputStream.read()阻塞问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022年中国青少年STEAM教育研究报
- 下一篇: 面试中,答不出产品方法论?4个方法教给你