Java NIO ByteBuffer:在读取完整消息之前先读取消息大小

Posted

技术标签:

【中文标题】Java NIO ByteBuffer:在读取完整消息之前先读取消息大小【英文标题】:Java NIO ByteBuffer : read the message size on head before read the complete message 【发布时间】:2012-07-12 14:48:05 【问题描述】:

我正在制作一个接收消息的 java NIO 服务器,每条消息在消息的头部都有它的大小,这就是为什么我首先读取一个具有默认大小(44)的缓冲区,然后获取完整大小从此缓冲区,然后创建一个新缓冲区,该缓冲区应该获取消息(正文)的其余部分,然后使用 System.arrayCopy() 制作包含完整消息的数组。此操作运行良好,问题是第二个缓冲区(消息体)具有大小但不包含正确的数据。 如果你有什么问题,请这是我的代码:

public void getMessageByMessageSize(SelectionKey key) 
    socket = (SocketChannel) key.channel();
    int nBytes = 0;
    byte[] message = null;
    try 
        nBytes = socket.read(headBuffer);
        if (nBytes < 0) 
            try 
                key.channel().close();
                key.cancel();
                return;
             catch (IOException e) 
                e.printStackTrace();
            
        
                    //size of the message body
        int corpMessageSize = MessageUtils.getMessageSize(headBuffer)
                - HEADER_SIZE;
        ByteBuffer corpsBuffer = ByteBuffer.allocate(corpMessageSize);
        headBuffer.flip();
        nBytes += socket.read(corpsBuffer);
        corpsBuffer.flip();
        byte[] corp=corpsBuffer.array();

        message = new byte[nBytes];
        System.arraycopy(headBuffer.array(), 0, message, 0, HEADER_SIZE);
        System.arraycopy(corpsBuffer.array(), 0, message, HEADER_SIZE,
                nBytes - HEADER_SIZE);
        System.out.println(nBytes);
        headBuffer.clear();
        corpsBuffer.clear();
     catch (IOException e) 
        e.printStackTrace();
        try 
            key.channel().close();
            key.cancel();
            return;
         catch (IOException ex) 
            e.printStackTrace();
        
    

    this.worker.verifyConnection(this,message, key);
    //this.worker.processData(this, socket, message, nBytes);

我有一个简单的客户端,它发送创建一个字节消息,在头部确定它的大小,然后发送它。

谢谢

【问题讨论】:

【参考方案1】:

nBytes += socket.read(corpsBuffer);

您假设这会读取整个消息并填充缓冲区。 TCP/IP 中没有任何东西可以保证这一点。你必须循环。如果您处于非阻塞模式,则必须重新选择是否获得零长度读取。

【讨论】:

与客户端我发送一个 50 字节的消息,44 字节的头部和 6 字节的数据字节,在服务器中我首先读取头部“nBytes”等于 44,然后提取从标题中获取大小并将“TOTAL_SIZE - HEADER_SIZE”分配给“corpsBuffer” nBytes += socket.read(corpsBuffer);读取 6 个字节(数据大小)并且“nBytes”等于 50,数据(6 个字节)我将它们设置为 0xff all ,并且来自 nBytes += socket.read(corpsBuffer);我得到 4 个字节的 0xff,最后两个字节是 0x00。我不认为我必须再次循环,但我会尝试一下,因为我真的被阻止了,谢谢 EJP 我想我得到了最后 4 个字节,而标题后面的两个字节丢失了,任何想法! @Fozix 我无法理解所有这些,但这很简单。要么你得到了整个请求体,要么你没有。如果没有,则必须循环,并且必须检查 read() 的结果才能知道您是否这样做了。

以上是关于Java NIO ByteBuffer:在读取完整消息之前先读取消息大小的主要内容,如果未能解决你的问题,请参考以下文章

Java--Stream,NIO ByteBuffer,NIO MappedByteBuffer性能对比

直接 java.nio.ByteBuffer 与 Java 数组性能测试

Java使用ByteBuffer读取大文件

java nio通过ByteBuffer输出文件信息

利用java.nio的FileChannel能够实现按行读取文件吗?(解决了)

80-10-015-原理-Java NIO-ByteBuffer