我需要使用(双向)请求 - 响应协议实现同时与多个客户端通信的应用程序。以前我使用两个专用线程为每个客户端(一个读取器/反应器和一个编写器/启动器)实现了这一点。这个问题是线程管理变得非常复杂和丑陋。有没有任何标准的处理方法,甚至只需要一个线程,或者至少有一定数量的线程来处理所有客户端?
这就是某些通信在具有阻塞实现的线程中的外观:
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。
答案 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)并按顺序处理响应。