从套接字输入流读取以错误的顺序返回数据

时间:2012-04-26 08:05:15

标签: java sockets inputstream

我正在通过套接字发送字节数组。发送的数据以4个字节开始,表示后续字节数组的长度。

// get the amount of data being sent
byte[] lengthOfReplyAsArray = new byte[4];
forceRead(inputStream, lengthOfReplyAsArray);
int lengthOfReply = byteArrayToInt(lengthOfReplyAsArray);

// read the data into a byte array
byte[] reply = new byte[lengthOfReply];
forceRead(inputStream, reply);

用于从InputStream读取数据的方法:

private byte[] forceRead(InputStream inputStream, byte[] result)
        throws IOException {

    int bytesRead = 0;
    int total = result.length;
    int remaining = total;

    while (remaining > 0)
        remaining -= inputStream.read(result, bytesRead, remaining);

    return result;

}

用于将字节数组转换为整数的方法:

private int byteArrayToInt(byte[] byteArray) {
    int result = 0;

    for (int i = 0; (i<byteArray.length) && (i<8); i++) {
        result |= (byteArray[3-i] & 0xff) << (i << 3);
    }
    return result;                  
}

问题是,数据没有按照它到达的顺序读取。正好读取前4个字节。剩下的就是混乱。我做了一个TCP转储,以确保数据正确到达客户端。好像数据被分成4个TCP数据包。 InputStream返回第一个数据包的前4个字节,然后是第四个数据包的整个数据,第二个数据包的最后一部分(从“最后一个数据包的长度”开始)和第三个数据包的整个数据。按此顺序。

有没有人知道可能导致此问题的原因?

1 个答案:

答案 0 :(得分:2)

您读取字节数组的逻辑不太正确:

docs

  

将输入流中最多len个字节的数据读入数组   字节。尝试读取len个字节,但更小   号码可能会被阅读。实际读取的字节数返回为   一个整数。

  

读取的第一个字节存储在元素b [off]中,下一个存入元素   b [off + 1],依此类推。读取的字节数最多等于   LEN。设k为实际读取的字节数;这些字节将是   存储在元素b [off]到b [off + k-1]中,留下元素   b [off + k]到b [off + len-1]不受影响。

但是,由于整个循环中bytesRead变量保持为0,因此输入流中的所有数据始终写入缓冲区的开头,覆盖已存在的数据。

什么会更好(检查-1还将确保如果流过早地耗尽数据导致remaining增加,则不会从剩余减去-1,这将意味着循环将不必要地运行,直到缓冲区溢出会使remaining为负):

while ((bytesRead = inputStream.read(result, total - remaining, remaining)) != -1
     && remaining > 0) {
    remaining -= bytesRead;