0

我正在编写我正在处理的应用程序的服务器组件。我正在使用 NIO 来处理网络,但我正在努力寻找一种有效的方式来处理阅读。客户端应用程序可以向服务器发送大小差异很大的数据包。它可以是 100 字节的文本消息,也可以是 500 KB 的图片,并且服务器需要能够处理这些数据包。通常,我会创建一个足够大的缓冲区以包含最大可能的数据包,但在这个应用程序的情况下,这意味着我可能必须有兆字节的缓冲区每个客户端的大小,这会吞噬内存。在和我的朋友讨论之后,我决定我想像使用旧 IO 一样处理这个问题。这意味着我将为每个数据包分配一个新缓冲区,该缓冲区的容量与传入数据包的长度完全相同。我的数据包结构如下:

[int] [length]
[byte] [opcode]
[byte...] [payload]

我的方法是有两个单独的缓冲区:一个容量为 4 的缓冲区来读取长度,另一个缓冲区将不断地以不同的容量重新初始化 - 数据包的长度。这是我想出的代码:

User user = (User) selectionKey.attachment();
SocketChannel socketChannel = user.getSocketChannel();
ByteBuffer readBuffer = user.getReadBuffer();
ByteBuffer lengthBuffer = user.getLengthBuffer();
/*
 * Read as many packets as possible.
 */
while (true) {
    /*
     * Read the length if it has not been read yet.
     */
    if (lengthBuffer.hasRemaining()) {
    socketChannel.read(lengthBuffer);
    /*
     * If the length could not be read, stop reading and wait for
     * more data to arrive.
     */
    if (lengthBuffer.hasRemaining()) {
        break;
    }
    } else {
    /*
     * Create a read buffer if one has not been created for the
     * incoming packet.
     */
    if (readBuffer == null) {
        lengthBuffer.flip();
        user.setReadBuffer(ByteBuffer.allocate(lengthBuffer
            .getInt()));
    }
    /*
     * Attempt to read the packet.
     */
    socketChannel.read(readBuffer);
    /*
     * If the packet was not completely read, then stop reading
     * altogether because all of the data has not been received yet.
     */
    if (readBuffer.hasRemaining()) {
        break;
    } else {
        /*
         * Otherwise, handle the data and prepare the buffers for
         * the next packet read.
         */
        readBuffer.flip();
        user.handleData();
        user.setReadBuffer(null);
        lengthBuffer.clear();
    }
    }
}

我看到了一些问题。一方面,我有时会在线收到 NullPointerException socketChannel.read(readBuffer)。除此之外,这个解决方案似乎并不干净。感觉代码里逻辑太多,好像有问题。有人可以为我提供一些修改或我的代码或完全不同的方法吗?我会很感激的。谢谢。

附带说明一下,任何人都可以在评论中发布一种将 Eclipse 中的代码粘贴到此处并正确格式化的好方法吗?我使用了代码按钮,但缩进仍然不正确,您可能已经注意到了。

4

2 回答 2

0

我建议你使用 netty 框架。因为它已经有处理这类问题的机制。看看这个

于 2013-04-02T17:41:06.963 回答
-1

您需要将连接视为字节流。TCP 中没有数据包这样的东西。服务器可能会向您发送 100 个字节,然后是 500 个字节,但它可能会一起到达接收器,一次一个字节,或者介于两者之间。因此,如果您的协议中有不同的消息,第一个要求是您能够自己拆分它们,就好像您是从文件而不是套接字中读取它们一样。在您将其构建到您的协议中之前,问题是无法解决的。

于 2013-04-02T22:57:25.213 回答