我有以下代码,它是选择器的一部分。
响应应该小于
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!!!!");
}
}
}
您的理解是正确的,一次只读取消息的一部分是可行的,特别是当消息以单独的块通过网络到达时。因此,有必要编写代码来应对部分读取。
使用
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
链接,以在读取响应时累积响应的各个部分。当遇到换行符时,认为响应已完成,此时可以根据需要进行处理。