我需要实现一个使用(双向)请求-响应协议与多个客户端同时通信的应用程序.以前,我为每个客户端使用两个专用线程(一个读取器/反应器和一个写入器/发起器)来实现此目的.问题是线程管理变得非常复杂和丑陋.是否有任何标准的处理方式,甚至可能只有一个线程,或者至少有恒定数量的线程来处理所有客户端?
这是使用阻塞实现的某种通信在线程中的外观:
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.
解决方法:
我认为使用某些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的某些事情不是自我解释的(至少对于我来说不是).但是,有几个易于操作的示例可以教您一些基础知识