Java阻塞套接字返回不完整的ByteBuffer

时间:2010-04-26 21:27:40

标签: java sockets nio

我有一个socketChannel配置为阻塞,但是当从这个套接字读取5K的字节缓冲区时,我有时会得到一个不完整的缓冲区。

    ByteBuffer messageBody = ByteBuffer.allocate(5*1024);
    messageBody.mark();
    messageBody.order(ByteOrder.BIG_ENDIAN);
    int msgByteCount = channel.read(messageBody);

偶尔,messageBody没有完全填充,并且channel.read()不返回-1或异常,而是读取的实际字节数(小于5k)。

有没有人遇到过类似的问题?

3 个答案:

答案 0 :(得分:4)

这就是读取工作的方式。 SocketChannel文档说:

  

读操作可能无法填充缓冲区,实际上它根本不会读取任何字节。 [...]但是,保证如果通道处于阻塞模式且缓冲区中至少有一个字节,则此方法将阻塞直到至少读取一个字节 [强调补充]。

答案 1 :(得分:1)

使用套接字时,必须预期套接字可能传输的字节数少于预期。您必须循环.read方法以获取剩余的字节。

通过套接字发送字节时也是如此。您必须检查已发送的字节数,并在发送时循环,直到所有字节都已发送。

此行为是由于网络层将邮件拆分为多个数据包。如果您的消息很短,那么您就不太可能遇到此消息。但是你应该总是为它编码。

每个缓冲区有5k字节,您很可能会看到发送方的消息吐出多个数据包。每次读取操作都将收到一个数据包,这只是您信息的一部分。

答案 2 :(得分:0)

TCP / IP以数据包形式发送信息,当您执行读取时它们并不总是可用,因此您必须循环读取。

           char [] buffer = new char[1024];
           int chars_read;
           try
           {
              while((chars_read = from_server.read(buffer)) != -1)
              {
                 to_user.write(buffer,0,chars_read);
                 to_user.flush();
              }
           }
           catch(IOException e)
           {
              to_user.println(e);
           }

See this post