Java套接字InputStream.read()的行为不符合预期

时间:2016-01-19 17:30:15

标签: java android sockets inputstream

我已经阅读了很多有关java InputStream和读取数据的教程和帖子。我已经建立了一个客户端和服务器实现,但我有一些奇怪的问题,其中读取可变长度"有效载荷"来自客户的不一致。

我想要做的是在一个逻辑有效负载中传输最大100kB。现在我已经验证TCP堆栈没有从客户端发送一个mahousive 100kB数据包。我根据之前关于InputStream读数的问题玩了不同的阅读形式,但我几乎试图让我的头发试图让它转储正确的数据。

比如说让客户端发送70k的有效载荷。

现在我注意到的第一个观察是,如果我从一个断点开始逐行流过代码,它将正常工作,我在出站字节[]中获得完全相同的计数。当自由运行时,每次运行具有几乎相同负载的代码时,byte []的大小都会不同。

时间问题?

第二个观察是当" inbuffer" size设置为4096,例如发生这种奇怪的行为。设置" inbuffer" size to 1表示正确的行为,即我得到正确的有效载荷大小。

请理解我不喜欢我必须让这个工作的方式,我对解决方案不满意。

您分别遇到过哪些经验,问题可能有助于我修复此代码,使其更可靠,更易于阅读。

    public void listenForResponses() {
    isActive = true;
    try {
        // apprently read() doesnt return -1 on socket based streams
        // if big stuff comes through, TCP packets are segmented, but the inputstream 
        // does something odd and doesnt return the correct raw data.
        // this is a work around to accept vari-length payloads into one byte[] buffer
        byte[] inBuffer = new byte[1];
        byte[] buffer = null;
        int bytesRead = 0;

        byte[] finalbuffer = new byte[0];

        boolean isMultichunk = false;

        InputStream istrm = currentSession.getInputStream();

        while ((bytesRead = istrm.read(inBuffer)) > -1 && isActive) {
            buffer = new byte[bytesRead];
            buffer = Arrays.copyOfRange(inBuffer, 0, bytesRead);

            int available = istrm.available();

            if(available < 1) {
                if(!isMultichunk) {
                    finalbuffer = buffer;
                }
                else {
                    finalbuffer = ConcatTools.ByteArrayConcat(finalbuffer,buffer);
                }
                notifyOfResponse(deserializePayload(finalbuffer));
                finalbuffer = new byte[0];
                isMultichunk = false;
            }
            else {
                if(!isMultichunk) {
                    isMultichunk = true;
                    finalbuffer = new byte[0];
                }
                finalbuffer = ConcatTools.ByteArrayConcat(finalbuffer,buffer);
            }

        }
    } catch (IOException e) {
        Logger.consoleOut("PayloadReadThread: " + e.getMessage());
        currentSession = null;
    }
}

1 个答案:

答案 0 :(得分:0)

InputStream按设计工作。

  

如果我从断点开始逐行流过代码,它将正常工作,我在出站字节[]中获得完全相同的计数。

这是因为逐步执行代码的速度较慢,因此读取之间的数据驱动量会增加,足以填满缓冲区。

  

当自由运行时,每次运行具有几乎相同负载的代码时,byte []的大小都会不同。

这是因为InputStream.read()被约束为阻塞,直到至少传输了一个字节,或者发生了EOS或异常。见Javadoc。填充缓冲区没有任何内容。

  

第二个观察是,当“inbuffer”大小设置为4096时,例如发生这种奇怪的行为。将“inbuffer”大小设置为1表示正确的行为,即我得到正确的有效负载大小。

对于1字节缓冲区,这是正确的行为,原因与上面给出的完全相同。这不是任何其他尺寸的'正确行为'。

注意你的复制循环是胡说八道。 availavle()几乎没有正确的用途,这不是其中之一。

while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

NB(2)read()确实在基于套接字的流上返回-1,但仅在对等方关闭或关闭连接时才返回。