2010-04-26 22 views
1

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

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

Ocasionally,消息体没有被完全填充和channel.read()不返回-1或者例外,但读取的字节的实际数目(小于5K)。

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

回答

3

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

读取操作可能不会填充缓冲区,实际上它可能根本不读取任何字节。 [...]然而,如果一个通道处于阻塞模式并且至少有一个字节保留在缓冲区中,那么这个方法会阻塞,直到读取至少一个字节 [加入的重点]。

+0

通过阅读API规范,我希望的是,读不返回,直到字节缓冲区填满(输入不是底层套接字缓冲区传递)。但是,这似乎并非如此。我会说API的实现是有问题的,因为阻塞套接字客户端需要填充缓冲区。 这是如果套接字完全为空并执行读操作会发生的情况。阅读将阻止,直到有东西到达。 无论如何,讨论帮助我解决了这个问题。非常感谢。 – user1069275 2010-04-27 15:13:24

+0

我不能说出你对文档的解释; “至少”对我来说似乎是非常明确的。从实际角度来看,您很少知道套接字将产生多少数据(不像文件),但您希望在数据到达时对其进行处理,如果数据比预期的要少,则不会永远阻止。 – Anon 2010-04-27 15:29:24

1

当您使用套接字时,您必须预测套接字传输的字节数可能会比您预期的要少。您必须在.read方法上循环才能获取剩余的字节。

当您通过套接字发送字节时也是如此。您必须检查发送了多少个字节,然后循环发送,直到发送完所有字节。

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

对于每个缓冲区5k字节,您很可能会看到发件人的邮件吐入多个数据包。每个读取操作将收到一个数据包,这只是您的消息的一部分。

+0

我认为阻塞套接字是为了避免你必须循环,但这并非100%真实。我将在读/写中添加循环。谢谢! – user1069275 2010-04-27 15:14:15

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

+0

谢谢!但问题是为什么不在写入操作中添加循环?我会这样做,因为它看起来阻塞套接字不是100%阻止反正。 – user1069275 2010-04-27 15:17:25

+0

@ evandro-carrenho - 更新后的文章,为什么你必须阅读一个循环 – 2010-04-27 18:01:41