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

SocketChannelImpl.write(ByteBuffer[] srcs, int offset, int length) appends ByteBuffer of size 0

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

我想知道这是否是由 SocketChannelImpl class 自动发送的某种 EOF 指示器,用于指示已完成发送一个字节缓冲区数组,以便在接收方接收到一个数组时ByteBuffers 后跟一个 size 0 的 BytBuffer 它知道它已经正确接收到从发送方发送的 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) 接收,但仍然需要额外调用 read(ByteBuffer src) 以读取 0 字节结尾。我(消息不灵通的)猜测那是某种 EOF 指示器,但从对问题的评论来看,这似乎与应用程序本身如何从通道读取数据有关。

SocketChannelImpl.write(ByteBuffer[] srcs, int offset, int length) appends ByteBuffer of size 0

不,不是。

I have a client-server application communicating over Java NIO sockets which makes use of the SocketChannelImpl class underneath.

忘了下面是什么。您正在使用 java.nio.channels.SocketChannel.

When from the senders side, I send a ByteBuffer array of length n elements

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

the client always receives ByteBuffer array of length n+1 elements with the last ByteBuffer always being of the size 0.

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

I was wondering if that is some sort of an EOF indicator automatically sent by the SocketChannelImpl class to indicate a completed send of an array of ByteBuffers

没有

so that when the receiving side receives an array ByteBuffers

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

followed by a ByteBuffer of size 0 it knows that it has correctly received the ByteBuffer array that was sent from the senders side?

这开始没有意义。 ByteBuffers既不发送也不接收,无论是单独还是作为数组。

Update: Adding example to further elaborate on my question:

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

Whenever a call to SocketChannel.write(ByteBuffer[] srcs, int offset, int length) is made on the senders side and SocketChannel.read(ByteBuffer srcs)

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

is made on the receivers side, I log the length of the array and the size of its element. Following is a set of logs from senders and receiver side:

Sender:

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

Receiver:

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

这只能说明两件事:

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

  1. 您使用了 read(ByteBuffer[] srcs),其中 srcs 包含三个 ByteBuffers:一个长度刚好为 4,一个长度 >= 1322,一个长度 > 0;只收到 1326 个字节,所以第三个 ByteBuffer 被清除,或者不受影响。

What I am asking is, why on the receiver side even though the amount of data that was sent by the sender(1326 bytes) is received by the client(4+1322), there is an extra call to the read(ByteBuffer src) is made which ends of reading 0 bytes.

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

My (ill informed) guess was that was some kind of an EOF indicator

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

but from the comments on the question it looks like that has to do something with how the application itself goes about reading data from the channels.

正确。您试图读取超出已发送数据末尾的内容,或者读取的内容 ByteBuffers 超出了保存已接收数据所需的内容。就这么简单。

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

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

所以在异步模式下,我们必须在开始时发送一些字节的 header 元数据,例如我们将要传输的数据大小,并且客户端将知道它之前必须调用多少次 read() 调用数据即将结束。