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)文章
解決Java中SimpleDateFormat線程不安全的五種方案
SimpleDateFormat 就是一個(gè)典型的線程不安全事例,本文主要介紹了解決Java中SimpleDateFormat線程不安全的五種方案,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05面試題:Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字
這篇文章主要介紹了Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07Spring更簡(jiǎn)單的存儲(chǔ)方式與獲取方式詳解
Spring是一個(gè)輕量級(jí)的IoC和AOP容器框架,是為Java應(yīng)用程序提供基礎(chǔ)性服務(wù)的一套框架,目的是用于簡(jiǎn)化企業(yè)應(yīng)用程序的開(kāi)發(fā),它使得開(kāi)發(fā)者只需要關(guān)心業(yè)務(wù)需求,下面這篇文章主要給大家介紹了關(guān)于Spring更簡(jiǎn)單的存儲(chǔ)方式與獲取方式的相關(guān)資料,需要的朋友可以參考下2022-06-06Java 8 Stream 的終極技巧——Collectors 功能與操作方法詳解
這篇文章主要介紹了Java 8 Stream Collectors 功能與操作方法,結(jié)合實(shí)例形式詳細(xì)分析了Java 8 Stream Collectors 功能、操作方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-05-05spring boot攔截器實(shí)現(xiàn)IP黑名單實(shí)例代碼
本篇文章主要介紹了spring boot攔截器實(shí)現(xiàn)IP黑名單實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04IntelliJ?IDEA?2023.2最新版激活方法及驗(yàn)證ja-netfilter配置是否成功
隨著2023.2版本的發(fā)布,用戶們渴望了解如何激活這個(gè)最新版的IDE,本文將介紹三種可行的激活方案,包括許可證服務(wù)器、許可證代碼和idea?vmoptions配置,幫助讀者成功激活并充分利用IDEA的功能,感興趣的朋友參考下吧2023-08-08springboot bean循環(huán)依賴實(shí)現(xiàn)以及源碼分析
最近在使用Springboot做項(xiàng)目的時(shí)候,遇到了一個(gè)循環(huán)依賴的 問(wèn)題,所以下面這篇文章主要給大家介紹了關(guān)于springboot bean循環(huán)依賴實(shí)現(xiàn)以及源碼分析的相關(guān)資料,需要的朋友可以參考下2021-06-06