在等待响应时,如何在不阻塞的情况下实现请求 - 响应协议?

时间:2011-10-22 12:50:17

标签: java networking concurrency protocols nonblocking

我需要使用(双向)请求 - 响应协议实现同时与多个客户端通信的应用程序。以前我使用两个专用线程为每个客户端(一个读取器/反应器和一个编写器/启动器)实现了这一点。这个问题是线程管理变得非常复杂和丑陋。有没有任何标准的处理方法,甚至只需要一个线程,或者至少有一定数量的线程来处理所有客户端?

这就是某些通信在具有阻塞实现的线程中的外观:

Command response = request("cmd1", "a", "b");
if(!response.is("OK")) {
    return;
}
response = request("cmd2", "c");
if(!response.is("OK")) {
    return;
}
response = request("cmd3");

在发送请求和等待相应响应之间,我希望当前线程能够执行其他工作,但是一旦响应实际到达,就继续执行。

我知道可以使用异步IO并在收到请求的响应后注册Java Future / Runnable实例,但这很容易变成匿名Runnable子类的多级嵌套,我怀疑它会更痛苦然后值得。这可能会导致类似下面的示例,它很快变得高度嵌套且不可读。当然必须有一个更简单的方法吗?

request("cmd1", "a", "b", new ResponseHandler() {
    public void response(Command response) {
        if(response.is("OK")) {
            request("cmd2", "c", new ResponseHandler() {
                public void response(Command response) {
                    if(response.is("OK")) {
                        request("cmd3", new NullResponseHandler());
                    }
                }});
        }
    }});

我还考虑过使用专用Actor framework来处理请求 - 响应逻辑的可能性。虽然看起来他们可以在这种情况下提供帮助,但我之前从未使用过这样的框架,所以我不知道它们是否适合这种情况。

简而言之,我的问题是:如何以非阻塞方式处理任意数量的请求 - 响应连接,以便恒定数量的线程足够? Actor框架是一种有效的方法吗?

PS。我在这个项目中使用Java。

2 个答案:

答案 0 :(得分:2)

我认为这应该是非常简单的使用一些Java NIO框架,例如netty。没有使用Actor框架,所以不知道这是不是更合适。

基本上,您创建了一个处理整个通信并存储必要信息的类 - 框架在后台处理整个线程,您只需提供一个方法,例如: messageReceived并在那里处理它。

缺点是,你必须基本上编写自己的状态机,这可能不是那么简单 - 但它肯定是使用NIO最简单的方法。

示例:

enum State {
    S0, S1
}
private State state = State.S0;
public void messageReceived(
        ChannelHandlerContext ctx, MessageEvent e) {
    switch(state) {
    case S0:
        // read object from channel and write appropriate response
        e.getChannel().write("HELO");  // writes are asynchronous 
        state = State.S1;
        break;
    case S1:
        // same as S0
        e.getChannel().write("DONE");
        break;
    }
}

请注意,阅读netty教程仍然是绝对必要的,因为有关NIO的事情并非自我解释(至少它们不适合我)。但是有几个很容易通过的例子可以教你基础知识。

答案 1 :(得分:1)

我认为使用Javas Non-Blocking IO是可行的方法。从那里你可以将响应添加到BlockingQueue中。然后可以有一个线程从BlockingQueue中获取项目(如果没有项目则为blokcing)并按顺序处理响应。