SocketChannelImpl.write(ByteBuffer [] srcs,int offset,int length)追加大小为0的ByteBuffer

时间:2017-09-13 02:53:25

标签: java nio bytebuffer socketchannel

我有一个客户端 - 服务器应用程序通过Java NIO套接字进行通信,它使用了下面的SocketChannelImpl类。当从发件人那边发送一个length n元素的ByteBuffer数组时,客户端总是接收length n+1元素的ByteBuffer数组,最后一个ByteBuffer始终是size 0

我想知道这是否是由SocketChannelImpl类自动发送的某种EOF指示符,以指示ByteBuffers数组的完成发送,以便当接收方接收到数组ByteBuffers后跟BytBuffer size 0它知道它已正确接收从发件人端发送的ByteBuffer数组吗?

更新:添加示例以进一步阐述我的问题:

每当在发送方进行SocketChannel.write(ByteBuffer [] srcs,int offset,int length)调用并在接收方进行SocketChannel.read(ByteBuffer srcs)时,我会记录数组的长度和它的元素的大小。以下是来自发件人和接收方的一组日志:

发件人:

Writing using:write(ByteBuffer[] srcs, int offset, int length)
srcs.length == 2, totalBytesWritten = 1326

接收器:

Read using read(ByteBuffer src)
totalBytesRead:4
totalBytesRead:1322
totalBytesRead:0

我要问的是,为什么在接收方,即使sender(1326 bytes)收到client(4+1322)发送的数据量,还有一个额外的呼叫{{1得到0字节的哪一端。我的(不明智的)猜测是某种EOF指标,但从问题的评论来看,它似乎必须对应用程序本身如何从通道中读取数据做些什么。

2 个答案:

答案 0 :(得分:2)

  

SocketChannelImpl.write(ByteBuffer[] srcs, int offset, int length)追加大小为0的ByteBuffer

不,它没有。

  

我有一个客户端 - 服务器应用程序通过Java NIO套接字进行通信,它使用了下面的SocketChannelImpl类。

忘记下面的内容。您正在使用java.nio.channels.SocketChannel

  

从发件人方面,我发送ByteBuffer长度为n个元素的数组

你不是。您发送内容。发送ByteBuffer[]数组被收集到一个字节流中并作为字节发送。

  

客户端始终会收到ByteBuffern+1个元素数组,其中ByteBuffer元素的大小始终为0。

不,它没有。接收到的字节将分散到另一个 ByteBuffer[]数组中,如果这是您用来读取通道的内容。如果使用gather-write和scatter-read,除了接收的实际字节之外,发送和接收ByteBuffer数组之间没有任何关系。

  

我想知道这是否是SocketChannelImpl类自动发送的某种EOF指示符,表示ByteBuffers

数组的已完成发送

没有

  

以便接收方收到数组ByteBuffers

它没有。它接收一个字节流,它自己提供的ByteBuffers数组。

  

后跟一个大小为0的ByteBuffer,它知道它已经正确接收了从发件人那边发送的ByteBuffer数组?

这并没有意义。 ByteBuffers既不是单独发送也不是单独接收。

  

更新:添加示例以进一步阐述我的问题:

这里没有例子,只有一些输出。一个例子很有用,但它必须包含Java代码。

  

每当在发件人方面拨打SocketChannel.write(ByteBuffer[] srcs, int offset, int length)SocketChannel.read(ByteBuffer srcs)

我们可以假设这应该是SocketChannel.read(ByteBuffer[] srcs)吗?否则它没有意义。

  

是在接收器端进行的,我记录了数组的长度和元素的大小。以下是来自发件人和接收方的一组日志:

     

发信人:

Writing using:write(ByteBuffer[] srcs, int offset, int length)
srcs.length == 2, totalBytesWritten = 1326
  

接收器:

Read using read(ByteBuffer src)
totalBytesRead:4
totalBytesRead:1322
totalBytesRead:0

这只能意味着两件事:

  1. 您使用了read(ByteBuffer src)并将其调用了三次;对等体只发送了1326个字节;所以第三次读取返回零,意味着没有数据可供读取。
  2. OR

    1. 您使用read(ByteBuffer[] srcs),其中srcs包含三个ByteBuffers:长度恰好为4,长度为> 1322,长度为> 0;仅收到1326个字节,因此第三个ByteBuffer已清除或未受影响。
    2.   

      我要问的是,为什么在接收方,即使发送方发送的数据量(1326字节)被客户端(4 + 1322)接收,也会额外调用{{ 1}}在读取0字节时结束。

      没有这样的调用,除非做了它,如果没有数据可以读取,你得到零字节。为什么这令人惊讶?

        

      我的(不明智的)猜测是某种EOF指标

      没有。 read(ByteBuffer src)返回-1表示流结束。

        

      但是从问题的评论看来,它必须对应用程序本身如何从频道中读取数据做些什么。

      正确。您试图读取已发送数据的末尾,或者比保存接收数据所需的read()更多ByteBuffers。就这么简单。

答案 1 :(得分:-1)

OS中的套接字(操作系统)是一个容量有限的缓冲区,因此如果您编写例如10 Kb的非OS数据将此10 Kb写入套接字作为一个块。 OS例如以1 Kb或其他值写入10个块,这取决于OS中的套接字配置。

因此我们可以在每次read()方法调用时读取不同数量的字节。而read()调用的主要内容取决于套接字读取方法的类型:同步或异步。在异步模式下读取困难 - 如果套接字在此时为空,这并不意味着我们读取所有数据它只是意味着在这个时候通道中没有数据但在下一次读取时我们可以读取例如10个字节,接下来的98个字节和下一个1098.

因此,在异步模式下,我们必须在开头发送一些字节元数据,例如我们将要传输的数据大小,客户端将知道在数据结束之前必须调用多少read()调用。 / p>