简体   繁体   English

如果缓冲区完全填满,AsynchronousSocketChannel 永远不会返回 read = -1

[英]AsynchronousSocketChannel never returns read = -1 if the buffer is completely filled

I'm experimenting reading data from HTTP requests我正在尝试从 HTTP 请求中读取数据

If my buffer size is 1024 bytes and the message coming in is 768 bytes, it works perfectly and I can see that the buffer is not full in which case I can assume that it's done如果我的缓冲区大小是 1024 字节并且传入的消息是 768 字节,那么它工作得很好,我可以看到缓冲区没有满,在这种情况下我可以假设它已经完成

read=692, buffer=java.nio.HeapByteBuffer[pos=692 lim=1024 cap=1024] :: read < cap

If my buffer size is 512, I can still determine when the request is done如果我的缓冲区大小是 512,我仍然可以确定请求何时完成

read=512, buffer=java.nio.HeapByteBuffer[pos=512 lim=512 cap=512]
read=160, buffer=java.nio.HeapByteBuffer[pos=160 lim=512 cap=512] :: read < cap

At buffer size 64, it still works在缓冲区大小为 64 时,它仍然有效

read=64, buffer=java.nio.HeapByteBuffer[pos=64 lim=64 cap=64]
...
read=64, buffer=java.nio.HeapByteBuffer[pos=64 lim=64 cap=64]
read=32, buffer=java.nio.HeapByteBuffer[pos=32 lim=64 cap=64] :: read < cap

When I go into the single digits, it appears that the channel is reading garbage data and filling up the buffer当我将 go 转换为个位数时,似乎通道正在读取垃圾数据并填满缓冲区

read=7, buffer=java.nio.HeapByteBuffer[pos=7 lim=7 cap=7]
...
read=7, buffer=java.nio.HeapByteBuffer[pos=7 lim=7 cap=7]
read=7, buffer=java.nio.HeapByteBuffer[pos=7 lim=7 cap=7] :: read == cap ?

This means I never know when all the data has been read With a buffer size of 7, I'm expecting the last one to be这意味着我永远不知道何时读取了所有数据 缓冲区大小为 7,我希望最后一个是

692 % 7 = 98 692 % 7 = 98

692 - (98*7) = 6 692 - (98*7) = 6

I'm expecting to see我期待看到

read=6, buffer=java.nio.HeapByteBuffer[pos=6 lim=7 cap=7]

but instead I'm seeing read=7但相反,我看到 read=7

If I make the buffer exactly the size of the http request, I'm seeing如果我使缓冲区的大小与 http 请求的大小完全相同,我会看到

read=692, buffer=java.nio.HeapByteBuffer[pos=692 lim=692 cap=692] :: read == cap ?

but it never goes back into the channel.read::completed until I refresh the browser, then read goes to -1, but then the next request hangs and never reaches read = -1 to trigger the channel close.但它永远不会回到 channel.read::completed 直到我刷新浏览器,然后 read 转到-1,但是下一个请求挂起并且永远不会达到 read = -1 以触发通道关闭。

read=692, buffer=java.nio.HeapByteBuffer[pos=692 lim=692 cap=692]
read=-1, buffer=java.nio.HeapByteBuffer[pos=0 lim=692 cap=692]
DONE, closing channel
read=692, buffer=java.nio.HeapByteBuffer[pos=692 lim=692 cap=692] << hangs here until refresh, but then the next request does the same again

Any ideas on how to make the "end-detection" more reliable?关于如何使“末端检测”更可靠的任何想法?

AsynchronousServerSocketChannel.open().let { server ->
        server.bind(InetSocketAddress(8080))

        // accept next socket
        server.accept(ByteBuffer.allocate(bufferSize), object : CompletionHandler<AsynchronousSocketChannel, ByteBuffer> {

            override fun completed(channel: AsynchronousSocketChannel, buffer: ByteBuffer) {

                // accept next
                server.accept(ByteBuffer.allocate(bufferSize), this)

                channel.read(
                    buffer,
                    channel,
                    object : CompletionHandler<Int, AsynchronousSocketChannel> {
                        override fun completed(read: Int, channel: AsynchronousSocketChannel) {

                            println(("read=$read, buffer=$buffer"))

                            if (read > 0 || buffer.position() > 0) {
                                buffer.rewind()
                                channel.read(
                                    buffer,
                                    channel,
                                    this
                                )
                            } else {
                                println("DONE, closing channel")
                                channel.close()
                            }
                        }
                        override fun failed(exception: Throwable, channel: AsynchronousSocketChannel) {
                            exception.printStackTrace()
                            channel.close()
                        }
                    }
                )
            }
            override fun failed(exception: Throwable, attachment: ByteBuffer?) {
                exception.printStackTrace()
            }
        })
    }

Your whole idea of detecting the end of the stream by reading less than the size of the buffer is entirely wrong.您通过读取小于缓冲区大小来检测 stream 结束的整个想法是完全错误的。

Sockets are not message-based, they're streams of data and data is not guaranteed to arrive as it was sent. Sockets 不是基于消息的,它们是数据流,不能保证数据在发送时到达。 When you send 692 bytes on one side, it may arrive as a single read of 692 bytes, but it could be eg two reads: 400 and 292 bytes.当您在一侧发送 692 字节时,它可能以 692 字节的单次读取到达,但也可能是两次读取:400 和 292 字节。 Even if the reading buffer is 1024 bytes.即使读取缓冲区是 1024 字节。

Two ways to detect the end of a stream are:检测 stream 结束的两种方法是:

  • Close the socket on the sending side, wait for -1 on receiving side.关闭发送端的套接字,等待接收端的-1
  • Implement some kind of a protocol (or use already existing one) to encode messages on top of the stream of data.实现某种协议(或使用现有协议)在 stream 数据之上对消息进行编码。 The easiest is to send the size of the message first and then read as long as we receive the expected amount of data.最简单的方法是先发送消息的大小,然后只要我们收到预期的数据量就读取。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM