日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

记录一次Socket的异常:InputStream.read()阻塞问题

發(fā)布時(shí)間:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记录一次Socket的异常:InputStream.read()阻塞问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

起先是在Socket編程時(shí),服務(wù)端取得客戶(hù)端發(fā)送的數(shù)據(jù),但是在InputStream.read()的時(shí)候,一直停在那,然后取了解了read方法才知道阻塞問(wèn)題

代碼示例:

//端口數(shù)據(jù)取得 byte[] b = new byte[1024]; in.read(b);//阻塞地方 String contents = new String(b).trim();//trim去除多余空格,否則,讀進(jìn)來(lái)的是byte[1024]個(gè)占位字節(jié)Logger.getLogger(Constant.TASK).info("端口數(shù)據(jù)取得:" + contents);

JAVA里的IO 目前有兩種,一種是早期發(fā)布的I/O模型,也就是所謂的BIO(Blocking I/O);另一種是JDK1.4里發(fā)布的基于 多路復(fù)用實(shí)現(xiàn)的NIO。

?

阻塞型 I/O,主要阻塞在兩個(gè)地方:

第一:在調(diào)用InutStream.read 方法是阻塞的,它會(huì)一直等到數(shù)據(jù)到來(lái)時(shí)(或超時(shí))才會(huì)返回;第二:在調(diào)用ServerSocket.accept()方法時(shí),也會(huì)一直阻塞到有客戶(hù)端連接才會(huì)返回;
?

目前大部分的客戶(hù)端服務(wù)端的網(wǎng)絡(luò)應(yīng)用軟件的早期版本的I/O都是使用阻塞型的I/O實(shí)現(xiàn)。

阻塞型的I/O 存在以下幾點(diǎn)問(wèn)題:

首先,InputStream.read()方法在其緩存區(qū)未滿(mǎn)時(shí),會(huì)造成阻塞,只有一定的數(shù)據(jù)填滿(mǎn)了緩存區(qū)或者客戶(hù)端關(guān)閉了套接字,方法才會(huì)返回。
其次,會(huì)產(chǎn)生大量的垃圾,BufferedReader創(chuàng)建了緩存區(qū)來(lái)從套接字中讀入數(shù)據(jù),但是同樣創(chuàng)建了一些字符串存儲(chǔ)這些數(shù)據(jù)。這些String很快變成垃圾需要回收。
類(lèi)似的,讀寫(xiě)操作被阻塞而且向流中一次寫(xiě)入一個(gè)字符會(huì)造成效率低下,所以應(yīng)該使用緩存區(qū),但一旦使用緩存,流又會(huì)產(chǎn)生更多是垃圾。
另外,通常在JAVA中處理阻塞I/O要用到線(xiàn)程(大量的線(xiàn)程),一般是實(shí)現(xiàn)一個(gè)線(xiàn)程池來(lái)處理請(qǐng)求。線(xiàn)程使得服務(wù)器可以處理多個(gè)連接,但是他們同樣也引發(fā)了許多問(wèn)題。每個(gè)線(xiàn)程擁有
自己的棧空間并且占用一些CPU時(shí)間,耗費(fèi)很大,而且很多時(shí)間是浪費(fèi)了阻塞I/O操作上,沒(méi)有有效利用CPU.次接收的操作是否結(jié)束了.???

可以看一下源碼

public abstract class InputStream extends Object implements Closeable

此抽象類(lèi)是表示字節(jié)輸入流的所有類(lèi)的超類(lèi)。

需要定義?InputStream?的子類(lèi)的應(yīng)用程序必須始終提供返回下一個(gè)輸入字節(jié)的方法。

個(gè)人理解,這種對(duì)象的概念有點(diǎn)像需要數(shù)據(jù)傳輸雙方之間的一個(gè)通道,這個(gè)通道負(fù)責(zé)接收數(shù)據(jù)(與之對(duì)應(yīng)還有OutPutStream 負(fù)責(zé)發(fā)送數(shù)據(jù))。

InputStream 中的read方法用于讀取數(shù)據(jù),方法有3個(gè)重載。

read()從輸入流讀取下一個(gè)數(shù)據(jù)字節(jié)。 read(byte[] b)從輸入流中讀取一定數(shù)量的字節(jié)并將其存儲(chǔ)在緩沖區(qū)數(shù)組 b 中。 read(byte[] b, int off, int len)將輸入流中最多 len 個(gè)數(shù)據(jù)字節(jié)讀入字節(jié)數(shù)組。

其中InputStream.read()方法,這個(gè)方法是從流里每次只讀取讀取一個(gè)字節(jié),效率會(huì)非常低。????

更好的方法是用InputStream.read(byte[] b)或者InputStream.read(byte[] b,int off,int len)方法,一次讀取多個(gè)字節(jié)。

這里有一點(diǎn)需要特別注意:read?方法在輸入數(shù)據(jù)可用、檢測(cè)到文件末尾或者拋出異常前,此方法一直阻塞。

Socket流這里還存在另外一個(gè)問(wèn)題,socket流和文件流不太一樣,文件流很容易知道文件末尾,到了文件末尾,直接就把流close掉就OK了。但是socket 流不一樣,你無(wú)法知道它什么時(shí)候到末尾,所以連接一直保持著,流也一直保持阻塞狀態(tài)。即使用了帶參數(shù)的read方法,返回了有效數(shù)據(jù),但其實(shí)流仍然沒(méi)有關(guān)閉,處于阻塞狀態(tài)。
針對(duì)這種請(qǐng)情況,一般就需要通信的雙方約定數(shù)據(jù)傳輸?shù)膮f(xié)議了。

①比如,約定消息的頭部首先明確此次傳輸數(shù)據(jù)的大小。這樣服務(wù)端就可以有目的性的讀取數(shù)據(jù)

如果采用一個(gè)一個(gè)字節(jié)讀取的話(huà),就需要先兩方約定好。不然就會(huì)造成read一直在阻塞狀態(tài)。

②采用InputStrea.shutdownOutput(),在客戶(hù)端的關(guān)閉Stream輸出,這樣服務(wù)端就不會(huì)一直在等待輸入流的輸入

這時(shí)候可以采用一次性讀取的read(b[])方法,注意的是b[]要不小于傳輸過(guò)來(lái)的數(shù)據(jù)大小,不然只會(huì)讀取其中一部分。

總結(jié)

以上是生活随笔為你收集整理的记录一次Socket的异常:InputStream.read()阻塞问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。