Java NIO:如何多次读入缓冲区?

问题描述 投票:0回答:1

我有以下代码,它是选择器的一部分。
响应应该小于

256
并且以换行符结束。 但据我了解,有可能(尽管我没有观察到这一点,因为消息非常小)只有部分消息准备好用于
OP_READ

如您所见,在读取时我会分配一个

Buffer
,读取它并转换为字符串。

处理部分消息的正确方法是什么?理想情况下,我想等待整个消息准备好后再阅读。一种简单的方法是使用

Map<SocketChannel, Buffer>
并读取直到连接关闭。

if (key.isReadable()) {
                        SocketChannel socketChannel = (SocketChannel) key.channel();

                        // Read the response from the server
                        ByteBuffer buffer = ByteBuffer.allocate(256);
                        int bytesRead = socketChannel.read(buffer);

                        if (bytesRead == -1) {
                            // The server closed the connection
                            socketChannel.close();
                            key.cancel();
                            channels.remove(socketChannel);
                        } else {
                            buffer.flip();
                            byte[] responseBytes = new byte[buffer.remaining()];
                            buffer.get(responseBytes);
                            String response = new String(responseBytes);
                            if (response.endsWith("\n")) {
                                socketChannel.close();
                                key.cancel();
                                channels.remove(socketChannel);
                                responses.add(response);
                                System.out.println(response);
                            } else {
                                System.out.println("need to read more!!!!");
                            }
                        }
                    }
java nonblocking java-nio
1个回答
0
投票

您的理解是正确的,一次只读取消息的一部分是可行的,特别是当消息以单独的块通过网络到达时。因此,有必要编写代码来应对部分读取。

使用

Map<SocketChannel, StringBuilder>
是在多次读取中收集数据的明智方法,直到您偶然发现换行符。这样,您可以附加部分读取的数据,并仅在读取整个消息后检查换行符。

这是对您的代码进行修改的示例,该修改将采用这种方法:

Map<SocketChannel, StringBuilder> partialResponses = new HashMap<>();

// Inside your loop...

if (key.isReadable()) {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    ByteBuffer buffer = ByteBuffer.allocate(256);
    int bytesRead = socketChannel.read(buffer);

    if (bytesRead == -1) {
        // The server closed the connection
        socketChannel.close();
        key.cancel();
        channels.remove(socketChannel);
    } else {
        buffer.flip();
        byte[] responseBytes = new byte[buffer.remaining()];
        buffer.get(responseBytes);
        String partialResponse = new String(responseBytes);

        // Append to the existing response if any, or start a new one
        StringBuilder responseBuilder = partialResponses.get(socketChannel);
        if (responseBuilder == null) {
            responseBuilder = new StringBuilder();
            partialResponses.put(socketChannel, responseBuilder);
        }
        responseBuilder.append(partialResponse);

        // Check for the line break indicating the end of the message
        if (partialResponse.endsWith("\n")) {
            String completeResponse = responseBuilder.toString();
            socketChannel.close();
            key.cancel();
            channels.remove(socketChannel);
            partialResponses.remove(socketChannel);
            responses.add(completeResponse);
            System.out.println(completeResponse);
        } else {
            System.out.println("need to read more!!!!");
        }
    }
}

在此代码中,一个

StringBuilder
对象与每个
SocketChannel
链接,以在读取响应时累积响应的各个部分。当遇到换行符时,认为响应已完成,此时可以根据需要进行处理。

© www.soinside.com 2019 - 2024. All rights reserved.