java socket大數(shù)據(jù)傳輸丟失問(wèn)題及解決
java socket大數(shù)據(jù)傳輸丟失
最近遇見(jiàn)一個(gè)問(wèn)題。利用java 的socket進(jìn)行數(shù)據(jù)傳輸時(shí),當(dāng)數(shù)據(jù)量過(guò)大,比如4w個(gè)字節(jié)。
這時(shí)候我在客戶端輸出流將數(shù)據(jù)發(fā)送給服務(wù)器。
服務(wù)器如果利用數(shù)組接收時(shí)(即is.read(byte[])方法),接收到的數(shù)據(jù)不全。網(wǎng)上解決方法。
一、分批發(fā)送,分批讀取,并不要直接讀取
將輸入輸出流利用BufferedInputStream包裝。
實(shí)測(cè)這種方法不能根本上解決問(wèn)題,治標(biāo)不治本。還是會(huì)有概率丟失。
二、實(shí)際上,數(shù)據(jù)是不會(huì)丟失的
即使輸入數(shù)據(jù)過(guò)大導(dǎo)致溢出。數(shù)據(jù)也不會(huì)丟失。
根據(jù)觀察,應(yīng)該只是數(shù)據(jù)還沒(méi)有傳輸過(guò)來(lái),但是利用is.read(byte[])方法時(shí),即使讀取到的數(shù)據(jù)不到byte[]數(shù)組長(zhǎng)度時(shí),該方法也可以進(jìn)行下去,不會(huì)阻塞?。?!
譬如以下代碼:
public class Test {
@org.junit.Test
public void server() throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
while (true){
Socket accept = serverSocket.accept();
InputStream is = accept.getInputStream();
byte[] bytes = new byte[5];
int len = is.read(bytes);
System.out.println(Arrays.toString(bytes));//發(fā)送端發(fā)送的數(shù)據(jù)只有兩個(gè)字節(jié),我們接收端設(shè)置為5個(gè)字節(jié)的字節(jié)數(shù)組,結(jié)果打印[1,2,0,0,0],而不會(huì)在上一步阻塞
}
}
@org.junit.Test
public void client() throws IOException {
Socket socket = new Socket("127.0.0.1",8080);
OutputStream os = socket.getOutputStream();
os.write(new byte[]{1,2});
}
}從這個(gè)例子我們就知道為什么會(huì)丟失數(shù)據(jù)了。
原因有兩點(diǎn):
- 網(wǎng)絡(luò)延時(shí)
- inputStream.read(byte[])方法讀取的數(shù)據(jù)長(zhǎng)度不一定等于byte[]數(shù)組長(zhǎng)度
根據(jù)以上兩點(diǎn),修改后的接收端代碼應(yīng)該如此。
public static byte[] readData(InputStream is,int length) throws IOException {
byte[] bytes = new byte[length];
int index = 0;
int len = 0;
while(index < length){
len = is.read(bytes,index,length - index);
//每次讀取完判斷數(shù)據(jù)是否全部讀取完畢
if(len > 0){
index += len;
}else {
break;
}
}
return bytes;
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot常用計(jì)量與bean屬性校驗(yàn)和進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則全面分析
這篇文章主要介紹了SpringBoot常用計(jì)量、bean屬性校驗(yàn)與進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-10-10
SpringBoot Bean被加載時(shí)進(jìn)行控制
很多時(shí)候我們需要根據(jù)不同的條件在容器中加載不同的Bean,或者根據(jù)不同的條件來(lái)選擇是否在容器中加載某個(gè)Bean,這就是Bean的加載控制,一般我們可以通過(guò)編程式或注解式兩種不同的方式來(lái)完成Bean的加載控制2023-02-02
程序包org.springframework.boot不存在的問(wèn)題解決
本文主要介紹了程序包org.springframework.boot不存在的問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09
spring boot 實(shí)現(xiàn)Minio分片上傳的步驟
分片上傳,就是將所要上傳的文件,按照一定的大小,將整個(gè)文件分隔成多個(gè)數(shù)據(jù)塊來(lái)進(jìn)行分別上傳,上傳完之后再由服務(wù)端對(duì)所有上傳的文件進(jìn)行匯總整合成原始的文件,本文給大家介紹spring boot 實(shí)現(xiàn)Minio分片上傳的步驟,感興趣的朋友跟隨小編一起看看吧2023-10-10
JVM自定義類(lèi)加載器在代碼擴(kuò)展性實(shí)踐分享
這篇文章主要介紹了JVM自定義類(lèi)加載器在代碼擴(kuò)展性實(shí)踐分享,一個(gè)類(lèi)型從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,到卸載出內(nèi)存為止,它的整個(gè)生命周期將會(huì)經(jīng)歷加載、驗(yàn)證、準(zhǔn)備、解析、初始化 、使用和卸載七個(gè)階段,其中驗(yàn)證、準(zhǔn)備、解析三個(gè)部分統(tǒng)稱為連接2022-06-06
Mybatis Plus條件構(gòu)造器ConditionConstructor用法實(shí)例解析
這篇文章主要介紹了Mybatis Plus條件構(gòu)造器ConditionConstructor用法實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
SpringBoot服務(wù)設(shè)置禁止server.point端口的使用
本文主要介紹了SpringBoot服務(wù)設(shè)置禁止server.point端口的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-01-01
Maven編譯報(bào)錯(cuò):未與 -source 8 一起設(shè)置引導(dǎo)類(lèi)路徑的完美解決方案
這篇文章主要為大家詳細(xì)介紹了Maven編譯報(bào)錯(cuò):未與 -source 8 一起設(shè)置引導(dǎo)類(lèi)路徑的相關(guān)解決方案,文中的示例代碼講解詳細(xì),有需要的小伙伴可以了解下2025-10-10
SpringBoot實(shí)現(xiàn)公共字段自動(dòng)填充的方法步驟
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)公共字段自動(dòng)填充的方法步驟,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-11-11

