我一直在使用AsychronousSockets,但是在运行大负载时遇到了收到ReadPendingException的问题。
一些背景:
我希望客户端将消息异步发送到服务器,然后侦听响应。
响应可以是3种类型之一,并且对AsynchronousSocketChannel的读取需要预定大小的ByteBuffer。
因此,我的解决方案是进行两次读取:一个首先接收消息的类型(以4个字节,一个int形式传入),然后是另一个读取,它将构造适当大小的字节缓冲区以处理消息的其余部分。
我认为这里的主要问题在于,当调用CompletetionHandler的complete方法时,并不一定意味着对ByteBuffer的读取已完成。为了解决这个问题,我创建了一个while循环,该循环将读取直到ByteBuffer填满。
但是,在while循环中的此读取似乎偶尔会与其他读取冲突,也就是我收到ReadPendingException时。
基本骨架代码:
AsynchronousChannelGroup mThreadGroup= AsynchronousChannelGroup.withFixedThreadPool(100, Executors.defaultThreadFactory());
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(mThreadGroup);
InetSocketAddress hostAddress = new InetSocketAddress("localhost", 12345);
// Connect to server
channel.connect(hostAddress, null, new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
// Write some message to server
ByteBuffer message = ...
channel.write(message, null, new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
// Now that we have sent the message, listen for a response type
ByteBuffer responseType = ...
channel.read(responseType, null, new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
// parse response type, do some other stuff...
// ...
// After other stuff, create new byte buffer for main message
ByteBuffer receiveMessage = ...
channel.read(receiveMessage, null, new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
// The read may not have been completed, so make sure that it is
while (receiveMessage.remaining() > 0) {
channel.read(receiveMessage);
}
// Handle receiveMessage...
}
@Override
public void failed(Throwable exc, Void attachment) {}
});
}
@Override
public void failed(Throwable exc, Void attachment) {}
});
}
public void failed(Throwable exc, Void attachment) {}
});
}
@Override
public void failed(Throwable exc, Void attachment) {}
});
因此,我的问题有两个:
有没有办法使代码如上所示正常工作(又不再收到ReadPendingException)?
有没有更好的方法来设置相同的功能?
预先感谢你们提供任何可能的帮助。
最佳答案
您不应在读取完成方法内部循环,尤其是在没有检查是否首先拥有所有数据的情况下。您应该首先检查是否已收到所需的所有数据,然后,如果尚未收到,则使用相同的完成方法再读一遍。该过程将递归进行,直到满足第一个测试为止。