首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用ReadPendingException时使用AsynchronousSocketChannel

使用ReadPendingException时使用AsynchronousSocketChannel
EN

Stack Overflow用户
提问于 2016-05-14 07:02:11
回答 2查看 1.6K关注 0票数 1

我一直在使用AsychronousSockets,但在运行大量负载时遇到了接收ReadPendingException的问题。

一些上下文:我希望客户端异步地向服务器发送消息,然后侦听响应。

响应可以是3种类型之一,AsynchronousSocketChannel的读取需要预定大小的ByteBuffer。

因此,我的解决方案是有两个读:一个先接收消息的类型(传入为4个字节,一个int),然后另一个读取,它将构造适当大小的字节缓冲区来处理消息的其余部分。

我认为,这里的主要问题在于,当调用CompletetionHandler的完整方法时,并不一定意味着ByteBuffer的读取是完全的。为了弥补这一点,我创建了一个will循环,它将读取到ByteBuffer已满为止。

然而,while循环中的这个读取似乎偶尔与其他读取发生冲突,这是在我接收到ReadPendingException时。

基本骨架代码:

代码语言:javascript
复制
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) {}
});

因此,我的问题有两方面:

  1. 是否有一种方法可以使代码(如上面所示)正确工作(也就是不再接收ReadPendingException)?
  2. 是否有更好的方法来设置相同的功能?

提前谢谢你们的帮助。

EN

回答 2

Stack Overflow用户

发布于 2016-05-19 04:01:40

您不应该在读取完成方法中循环,特别是不首先检查是否有所有数据。您应该首先检查是否收到了所需的所有数据,如果没有,则使用相同的完成方法再进行一次读取。这一过程将恢复,直到它满足第一次测试。

票数 1
EN

Stack Overflow用户

发布于 2016-05-17 05:11:56

我认为这个异常的出现是因为另一个线程正在尝试调用这个completionHandler。访问将需要在readCompletionHandler上同步。或者,尝试删除ReadCompletionHandler中的while(剩余)循环。使用bytesRead参数调用已完成的回调函数。使用此值创建读取消息的缓冲区。例如:

` class ClientReadCompletionHandler实现CompletionHandler {

代码语言:javascript
复制
private AsynchronousSocketChannel socket;
private ByteBuffer readBuffer;

public ClientReadCompletionHandler(AsynchronousSocketChannel socket, ByteBuffer readBuffer) {
    this.socket = socket;
    this.readBuffer = readBuffer;
    System.out.println("readBuffer in constructor: " + readBuffer);
}

@Override
public void completed(Integer bytesRead, IOContext state) {
    if (bytesRead != null && bytesRead == -1) {
        try {
            socket.close();
            return;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    byte[] buffer = new byte[bytesRead];
    readBuffer.rewind();
    // Rewind the input buffer to read from the beginning

    readBuffer.get(buffer);

    if(readBuffer.hasRemaining()) {
        // process this readBuffer somehow to read all remaining data.
        // This will not be the place to call socket.read() again.

    }      
        readBuffer.clear();
        IOContext readState = new IOContext();  
   // Now read from socket again.
        socket.read(readBuffer, readState, this);
}

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37223693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档