异步NIO:同一客户端向服务器发送多条消息

时间:2012-10-22 18:52:41

标签: java sockets concurrency nio2

关于Java NIO2。

假设我们有以下内容来收听客户请求...

asyncServerSocketChannel.accept(null, new CompletionHandler <AsynchronousSocketChannel, Object>() {
    @Override
    public void completed(final AsynchronousSocketChannel asyncSocketChannel, Object attachment) {
         // Put the execution of the Completeion handler on another thread so that 
         // we don't block another channel being accepted.
         executer.submit(new Runnable() {
             public void run() {
                 handle(asyncSocketChannel);
             }
         });

         // call another.
         asyncServerSocketChannel.accept(null, this);
     }

     @Override
     public void failed(Throwable exc, Object attachment) {
         // TODO Auto-generated method stub
     }
});

此代码将接受客户端连接进程,然后接受另一个。 要与服务器通信,客户端将打开AsyncSocketChannel并触发消息。 然后调用Completion处理程序completed()方法。

但是,这意味着如果客户端想要在同一个AsyncSocket实例上发送另一个消息,则不能。

它必须创建另一个AsycnSocket实例 - 我认为这意味着另一个TCP连接 - 这会影响性能。

任何想法如何解决这个问题?

或者以另一种方式提出问题,任何想法如何使同样的asyncSocketChannel接收多重CompleteionHandler completed()事件?

编辑: 我的处理代码是这样的......

public void handle(AsynchronousSocketChannel asyncSocketChannel) {
    ByteBuffer readBuffer = ByteBuffer.allocate(100);
    try {
        // read a message from the client, timeout after 10 seconds 
        Future<Integer> futureReadResult = asyncSocketChannel.read(readBuffer);
        futureReadResult.get(10, TimeUnit.SECONDS);
        String receivedMessage = new String(readBuffer.array());

        // some logic based on the message here...               

        // after the logic is a return message to client
        ByteBuffer returnMessage = ByteBuffer.wrap((RESPONSE_FINISHED_REQUEST + " " + client
                 + ", " + RESPONSE_COUNTER_EQUALS + value).getBytes());
        Future<Integer> futureWriteResult = asyncSocketChannel.write(returnMessage);
        futureWriteResult.get(10, TimeUnit.SECONDS);
   } ...

这就是我的服务器从异步通道读取消息并返回一个答案。 客户端阻止,直到它得到答案。但这没关系。我不在乎客户阻止。

完成此操作后,客户端会尝试在同一个异步通道上发送另一条消息,但它不起作用。

2 个答案:

答案 0 :(得分:3)

有两个连接阶段和两种不同类型的完成处理程序。 第一阶段是处理连接请求,这是您编写的(BTW,如Jonas所说,不需要使用其他执行程序)。第二阶段(可以重复多次)是发出I / O请求并处理请求完成。为此,您必须提供一个内存缓冲区来保存要读取或写入的数据,并且您没有显示任何代码。当你进行第二阶段时,你会发现你写的没有这样的问题:“如果客户端想要在同一个AsyncSocket实例上发送另一个消息,那就不能了。”

NIO2的一个问题是,一方面,程序员必须避免在同一个通道上进行同一类型的多个异步操作(接受,读取或写入)(否则会发生错误),另一方面,程序员必须避免在处理程序中阻塞等待。这个问题在df4j actor framework的df4j-nio2子项目中得到解决,其中AsyncServerSocketChannel和AsyncSocketChannel都表示为actor。 (df4j由我开发。)

答案 1 :(得分:1)

首先,您不应该使用completed方法中的执行器。 completed - 方法已在新的工作线程中处理。

completed的{​​{1}}方法中,您应该致电.accept(...)来阅读数据。客户端可以在同一个套接字上发送另一条消息。此消息将通过对asychSocketChannel.read(...) - 方法的新调用来处理,可能由服务器上的另一个工作线程处理。