最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java Socket無法完全接收返回內(nèi)容的解決方案

 更新時(shí)間:2021年10月27日 14:19:51   作者:LVXIANGAN  
這篇文章主要介紹了java Socket無法完全接收返回內(nèi)容的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

最近在使用Socket通訊時(shí),遇到了接收內(nèi)容不全(返回內(nèi)容 = 4字節(jié)報(bào)文長度 + 內(nèi)容主體)的問題:客戶端發(fā)送請(qǐng)求數(shù)據(jù),服務(wù)器明明返回了73個(gè)字節(jié)內(nèi)容,但客戶端有時(shí)能全部接收,但有時(shí)卻只能返回4個(gè)字節(jié)。

一開始是懷疑服務(wù)器返回有問題,但使用調(diào)試工具連續(xù)測(cè)試了很多次,結(jié)果顯示:服務(wù)器的確每次都返回了73個(gè)字節(jié)內(nèi)容。那很明顯了,問題出現(xiàn)在客戶端代碼上。

錯(cuò)誤現(xiàn)象

再來看看調(diào)試工具結(jié)果:

讓我們來看看客戶端代碼,調(diào)用方法如下:(該方法適用于返回報(bào)文前兩個(gè)字節(jié)表示長度的情況:2字節(jié)報(bào)文長度 + 內(nèi)容主體)

public static void test() {
		SocketClient client = new SocketClient();
		// 建立socket對(duì)象
		int iret = client.connect("192.168.1.105", 1234);
		if (iret == 0) {
			// 發(fā)送數(shù)據(jù)
			client.write("helloworld".getBytes());
			// 接收數(shù)據(jù)
			byte data[] = client.read();
			if ((data != null) && (data.length != 0)) {
				// 處理接收結(jié)果
				Utils.print("響應(yīng)報(bào)文字節(jié)數(shù)組---->" + Arrays.toString(data));
			}
		}		
	}

SocketClient.java源碼:

public class SocketClient { 
	// 存儲(chǔ)接收數(shù)據(jù)
	private byte m_buffer[] = new byte[0x10000];
	private Socket m_socket;
	private InputStream m_inputstream;
	private OutputStream m_outputstream;
	private BufferedInputStream m_bufferedinputstream;
	private BufferedOutputStream m_bufferedoutputstream;
	private boolean connected; 
	public int connect(String host, int port) {
		try {
			SocketAddress socketAddress = new InetSocketAddress(host, port);
			m_socket = new Socket();
			m_socket.connect(socketAddress, 5000);
			m_socket.setSoTimeout(60000);
 
			m_inputstream = m_socket.getInputStream();
			m_bufferedinputstream = new BufferedInputStream(m_inputstream);
			m_outputstream = m_socket.getOutputStream();
			m_bufferedoutputstream = new BufferedOutputStream(m_outputstream);
		} catch (Exception e) {
			return -1;
		}
		connected = true;
		return 0;
	}
 
	/**
	 * 發(fā)送請(qǐng)求數(shù)據(jù)
	 * 
	 * @param data
	 * @param start
	 * @param end
	 * @return
	 */
	public int write(byte data[]) {
		if (data == null || data.length == 0 || !connected) {
			return 0;
		}
		try {
			m_bufferedoutputstream.write(data, 0, data.length);
			m_bufferedoutputstream.flush();
		} catch (Exception e) {
			return -1;
		}
		return 0;
	}
	
	/**
	 * 讀取返回?cái)?shù)據(jù)
	 * 
	 * @return
	 */
	public byte[] read() {
		if (!connected) {
			return null;
		}
		int len = -1;
		try {
			// 長度不正確,有時(shí)返回4,有時(shí)返回73
			len = m_bufferedinputstream.read(m_buffer, 0, 0x10000);
		} catch (Exception e) {
			len = 0;
		}
		if (len != -1) {
			return null;
		} else {
			byte ret[] = new byte[len];
			for (int i = 0; i < len; i++) {
				ret[i] = m_buffer[i];
			}
			return ret;
		}
	}
}

通過代碼調(diào)試,發(fā)現(xiàn)問題出現(xiàn)在inputsream.read方法上,java API對(duì)其描述如下:

int java. io. BufferedInputStream.read( byte[] buffer, int offset, int byteCount) throws IOException

Reads at most byteCount bytes from this stream and stores them in byte array buffer starting at offset offset. Returns the number of bytes actually read or -1 if no bytes were read and the end of the stream was encountered. If all the buffered bytes have been used, a mark has not been set and the requested number of bytes is larger than the receiver's buffer size, this implementation bypasses the buffer and simply places the results directly into buffer.

Overrides: read(...) in FilterInputStream
Parameters:
buffer the byte array in which to store the bytes read.
offset the initial position in buffer to store the bytes read from this stream.
byteCount the maximum number of bytes to store in buffer.
Returns:
the number of bytes actually read or -1 if end of stream.
Throws:
IndexOutOfBoundsException - if offset < 0 or byteCount < 0, or if offset + byteCount is greater than the size of buffer.
IOException - if the stream is already closed or another IOException occurs.

引起錯(cuò)誤原因在于

客戶端在發(fā)送數(shù)據(jù)后,過快地執(zhí)行read操作,而這時(shí)服務(wù)端尚未完全返回全部?jī)?nèi)容,因此只能讀到部分字節(jié)。于是換了個(gè)思路:

public class SocketClient { 
	private Socket m_socket;
	private InputStream m_inputstream;
	private OutputStream m_outputstream;
	private BufferedInputStream m_bufferedinputstream;
	private BufferedOutputStream m_bufferedoutputstream;
	private boolean connected; 
	public int connect(String host, int port) {
		try {
			SocketAddress socketAddress = new InetSocketAddress(host, port);
			m_socket = new Socket();
			m_socket.connect(socketAddress, 5000);
			m_socket.setSoTimeout(60000);
 
			m_inputstream = m_socket.getInputStream();
			m_bufferedinputstream = new BufferedInputStream(m_inputstream);
			m_outputstream = m_socket.getOutputStream();
			m_bufferedoutputstream = new BufferedOutputStream(m_outputstream);
		} catch (Exception e) {
			return -1;
		}
		connected = true;
		return 0;
	}
 
	/**
	 * 發(fā)送請(qǐng)求數(shù)據(jù)
	 * 
	 * @param data
	 * @param start
	 * @param end
	 * @return
	 */
	public int write(byte data[]) {
		if (data == null || data.length == 0 || !connected) {
			return 0;
		}
		try {
			m_bufferedoutputstream.write(data, 0, data.length);
			m_bufferedoutputstream.flush();
		} catch (Exception e) {
			return -1;
		}
		return 0;
	}
	
	/**
	 * 讀取返回?cái)?shù)據(jù)
	 * 
	 * @return
	 */
	public byte[] read() {
		if (!connected) {
			return null;
		}
		try {
			return readStream(m_bufferedinputstream);
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * @功能 讀取流
	 * @param inStream
	 * @return 字節(jié)數(shù)組
	 * @throws Exception
	 */
	public static byte[] readStream(InputStream inStream) throws Exception {
		ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = inStream.read(buffer)) != -1) {
			outSteam.write(buffer, 0, len);
		}
		outSteam.close();
		inStream.close();
		return outSteam.toByteArray();
	}
	
	public static void test() {
		SocketClient client = new SocketClient();
		// 建立socket對(duì)象
		int iret = client.connect("192.168.1.105", 1234);
		if (iret == 0) {
			// 發(fā)送數(shù)據(jù)
			client.write("helloworld".getBytes());
			// 接收數(shù)據(jù)
			byte data[] = client.read();
			if ((data != null) && (data.length != 0)) {
				// 處理接收結(jié)果
				Utils.print("響應(yīng)報(bào)文字節(jié)數(shù)組---->" + Arrays.toString(data));
			}
		}		
	}
}

測(cè)試通過.....

可參考以下解決思路

protected byte[] readMessage(BufferedInputStream is) throws IOException {
		//        MyLog.d(TAG,"=======>readMessage--inputStream=" );
		        int offset = 0;
		        int messageStartOffset = -1;
		        int wait = 0;
		        int messageEndOffset = -1;
		        int findStartOffset = -1;
 
		        while(messageEndOffset==-1||(messageEndOffset+2)>offset){
		            if(is.available()==0){
		                try {
		                    Thread.sleep(MESSAGE_WAIT_INTERVAL);
		                    wait += MESSAGE_WAIT_INTERVAL;
		                } catch (InterruptedException ex) {
		                }
		                if(wait>=MESSAGE_OVERTIME){
		                //超時(shí)錯(cuò)誤
		                    throw new RuntimeException(EXCEPTION_TIMEOUT);
		                }
		                continue;
		            }
		            
		            offset += is.read(messageBuffer, offset, is.available());//讀出數(shù)據(jù)
		            TestMessage.showBytes(messageBuffer, 0, offset, "MESSAGE");
		            if(messageStartOffset==-1){ //未找到報(bào)文頭
		                if(findStartOffset<0)
		                    findStartOffset = 0;
		                messageStartOffset = findStartOffset(messageBuffer, findStartOffset, offset);//查找報(bào)文頭
		                MyLog.e(TAG, "messageStartOffset="+messageStartOffset);
		                if(messageStartOffset>=0){//找到報(bào)文頭
		                    if(messageStartOffset<2){
		                        //報(bào)文錯(cuò)誤
		                        throw new RuntimeException(EXCEPTION_MSG_PARSE_ERROR);
		                    }else{
		                        int iMessageLength = ((messageBuffer[messageStartOffset-2]&0xff)<<8)+
		                         (messageBuffer[messageStartOffset-1]&0xff);
		//                        MyLog.e(TAG, "iMessageLength="+iMessageLength);
		                        int ignoreInvalidLength = messageStartOffset-4;
		                        messageEndOffset = iMessageLength + ignoreInvalidLength;
		//                        MyLog.e(TAG, "messageStartOffset="+messageStartOffset);
		                        MyLog.e(TAG, "messageEndOffset="+messageEndOffset);

如果想要讓程序保證讀取到count個(gè)字節(jié),最好用以下代碼:

int count = 100;  
byte[] b = new byte[count];  
int readCount = 0; // 已經(jīng)成功讀取的字節(jié)的個(gè)數(shù)  
while (readCount < count) {  
    readCount += inStream.read(b, readCount, count - readCount);  
}  

這樣就能保證讀取100個(gè)字節(jié),除非中途遇到IO異?;蛘叩搅藬?shù)據(jù)流的結(jié)尾情況!

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中的權(quán)重算法(如Dubbo的負(fù)載均衡權(quán)重)詳解

    Java中的權(quán)重算法(如Dubbo的負(fù)載均衡權(quán)重)詳解

    這篇文章主要介紹了Java中的權(quán)重算法(如Dubbo的負(fù)載均衡權(quán)重)詳解,負(fù)載均衡,其含義就是指將負(fù)載進(jìn)行平衡、分?jǐn)偟蕉鄠€(gè)操作單元上進(jìn)行運(yùn)行,例如FTP服務(wù)器、Web服務(wù)器、企業(yè)核心應(yīng)用服務(wù)器和其它主要任務(wù)服務(wù)器等,從而協(xié)同完成工作任務(wù),需要的朋友可以參考下
    2023-08-08
  • 老生常談spring?boot中的定時(shí)任務(wù)

    老生常談spring?boot中的定時(shí)任務(wù)

    SpringBoot中的定時(shí)任務(wù)主要通過@Scheduled注解以及SchedulingConfigurer接口實(shí)現(xiàn),本文給大家介紹spring?boot中的定時(shí)任務(wù),感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • Spring Boot+Nginx實(shí)現(xiàn)大文件下載功能

    Spring Boot+Nginx實(shí)現(xiàn)大文件下載功能

    相信很多小伙伴,在日常開放中都會(huì)遇到大文件下載的情況,大文件下載方式也有很多,比如非常流行的分片下載、斷點(diǎn)下載;當(dāng)然也可以結(jié)合Nginx來實(shí)現(xiàn)大文件下載,在中小項(xiàng)目非常適合使用,這篇文章主要介紹了Spring Boot結(jié)合Nginx實(shí)現(xiàn)大文件下載,需要的朋友可以參考下
    2024-05-05
  • 解決MyBatis Mapper的XML文件SQL語句無法自動(dòng)提示問題(親測(cè)有效)

    解決MyBatis Mapper的XML文件SQL語句無法自動(dòng)提示問題(親測(cè)有效)

    這篇文章主要給大家介紹了如何解決MyBatis Mapper的XML文件SQL語句無法自動(dòng)提示的問題,文中有詳細(xì)的原因分析,以及通過圖文介紹的解決方案,需要的朋友可以參考下
    2023-10-10
  • Java實(shí)現(xiàn)簡(jiǎn)易拼圖游戲的方法詳解

    Java實(shí)現(xiàn)簡(jiǎn)易拼圖游戲的方法詳解

    這篇文章主要介紹了如何利用Java語言實(shí)現(xiàn)簡(jiǎn)易拼圖游戲,幫助大家更好的理解和使用Java開發(fā)游戲,感興趣的朋友可以跟隨小編一起學(xué)習(xí)一下
    2022-05-05
  • 聊聊Spring——AOP詳解(AOP概覽)

    聊聊Spring——AOP詳解(AOP概覽)

    這篇文章主要介紹了Spring——AOP詳解(AOP概覽),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 基于AspectJ注解方式實(shí)現(xiàn)AOP

    基于AspectJ注解方式實(shí)現(xiàn)AOP

    這篇文章主要介紹了基于AspectJ注解方式實(shí)現(xiàn)AOP,使用AspectJ的注解可以更方便地編寫和管理切面邏輯,而Spring AOP也是使用了AspectJ提供的注解來實(shí)現(xiàn)切面編程,需要的朋友可以參考下
    2023-09-09
  • SpringBoot+RabbitMQ實(shí)現(xiàn)消息可靠傳輸詳解

    SpringBoot+RabbitMQ實(shí)現(xiàn)消息可靠傳輸詳解

    消息的可靠傳輸是面試必問的問題之一,保證消息的可靠傳輸主要在生產(chǎn)端開啟?comfirm?模式,RabbitMQ?開啟持久化,消費(fèi)端關(guān)閉自動(dòng)?ack?模式。本文將詳解SpringBoot整合RabbitMQ如何實(shí)現(xiàn)消息可靠傳輸,需要的可以參考一下
    2022-05-05
  • java基礎(chǔ)學(xué)習(xí)JVM中GC的算法

    java基礎(chǔ)學(xué)習(xí)JVM中GC的算法

    這篇文章主要介紹了java基礎(chǔ)學(xué)習(xí)JVM中GC的算法,通過圖文加深對(duì)GC算法思路的理解。
    2017-11-11
  • java線程的基礎(chǔ)實(shí)例解析

    java線程的基礎(chǔ)實(shí)例解析

    java中線程的基本方法的熟練使用是精通多線程編程的必經(jīng)之路,線程相關(guān)的基本方法有wait,notify,notifyAll,sleep,join,yield等,本文淺要的介紹一下它們的使用方式
    2021-06-06

最新評(píng)論

兴业县| 新泰市| 吉首市| 秦安县| 巴林左旗| 武隆县| 彰化市| 普定县| 米林县| 康定县| 团风县| 隆回县| 烟台市| 沙河市| 固原市| 平塘县| 梧州市| 高安市| 卓尼县| 新津县| 彩票| 论坛| 西畴县| 天峨县| 黔江区| 巴林左旗| 泌阳县| 宝坻区| 万载县| 曲麻莱县| 韶山市| 城市| 南昌市| 竹北市| 武汉市| 高州市| 微博| 宝山区| 井研县| 峨山| 仙居县|