socket通信報文接受不完整或者接收不到的問題

一、問題描述:
socket通信中經常會遇到返回報文接收不全甚至完全沒有接收到的問題。

二、解決方案:
發送方在報文頭用固定長度的字節聲明該報文正文長度,注意這裏的報文正文不包括表示報文長度的字符串本身。接收方在接收報文時先按約定讀取報文長度的聲明,轉換爲數字類型,再根據該長度讀取報文內容,以避免漏讀的情況。

三、代碼實現(Java):
以8位長度的報文頭表示報文正文長度爲例,此時報文接收方的示例代碼如下:

import java.io.*;
import java.net.Socket;

/**
 * Created by linghan on 2018/12/20.
 */
public class SocketClient{

    public static String ReceiveXml(){

        DataOutputStream out = null;
        Socket socket = null;
        BufferedWriter bufferedWriter = null;
        String returnXml="";
        try {
            socket = new Socket("localhost", 9999);
            int headLen = 8;   //約定的報文頭長度
            char [] xmlLen = new char[headLen];
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
            int curHeadLength = 0;
            while(curHeadLength < headLen){
                int readLen = bufferedReader.read(xmlLen,curHeadLength,headLen-curHeadLength);
                 //注意這裏的判斷不能省略 因爲當報文結束時read()方法返回值爲-1  此時如果我們讀到的結束符 , readLen 就會被賦值爲-1 ,那麼循環就會繼續,結果就會造成xmlLen數組的下標越界,自然會得到錯誤的結果
                if(readLen < 0){  
                    break;
           }
                curHeadLength += readLen;
            }
            int bodyLength = Integer.parseInt(new String(xmlLen));
            char [] xml = new char[bodyLength];
            int curBodyLength = 0;
            while(curBodyLength < bodyLength){
                int readLen2 = bufferedReader.read(xml,curBodyLength,bodyLength-curBodyLength);
                if(readLen2 < 0){
                    break;
                }
                curBodyLength += readLen2;
            }
            returnXml = new String(xml);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NumberFormatException e){
            e.printStackTrace();
        }finally{
            try {
                socket.close();
                out.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        return returnXml;
    }
}

四、read(char cbuf[], int off, int len)方法詳解:
該方法的作用就是從接收內容的第off個字符開始,最多讀取len個長度存進cbuf這個數組中,注意這裏是以追加的形式存到數組裏的。爲什麼len是最多讀取的意思呢,當可供讀取的長度大於等於len的時候,直接讀取len個,當可供讀取的長度不足len的時候,有多少讀多少。

測試代碼:

//報文發送方發送如下內容
String returnxml = "1AAAAAAAAA2BBBBBBBBB3CCCCCCCCC4DDDDDDDDD5EEEEEEEEE";
			bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8"));
			bufferedWriter.write(returnxml);
			bufferedWriter.flush();
			socket.shutdownOutput();
//報文接收方每次讀取10位長度
int headLen = 50;
            char[] xml = new char[headLen];
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
            int curHeadLength = 0;
            while (curHeadLength < headLen) {
                int readLen = bufferedReader.read(xml, curHeadLength,10);
                System.out.println("讀取長度:" + readLen + "   字節數組的內容:" + new String(xml));
                if (readLen < 0) {
                    break;
                }
                curHeadLength += readLen;
            }
            System.out.println("數組的最終內容:" + new String(xml));

接收方運行結果:
此結果可證明read()方法中的數組參數,是以追加的方式被賦值的。

轉載請註明出處,如有錯誤歡迎指正!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章