我正在尝试使用 Apache Camel 来实现 TCP 游戏服务器。它将接受来自多个人类或机器人玩家的双向、同步 telnet 或 SSH 连接。
通信“协议”有点粗糙,并且基于早期版本中已经存在的遗留基础设施。基本上,客户端和服务器通过套接字交换 I/O(每个客户端一个连接)。
通常,这由单行命令字符串或单行响应字符串组成。但是,在某些情况下,输入或输出可以跨越多个换行符,然后才被视为“完整”并准备好接受对方的响应。所以我的计划是:
使用 Spring Boot 和 Apache Camel 创建 TCP 套接字服务器,并使用后者的“Netty4”组件。
使用聚合从套接字连接收集传入的文本行。根据检测到的输入类型,将它们汇总为一行或多行的消息。
将生成的消息传递给端点,端点解析输入并将适当的响应返回给套接字。
我可以显示任何其他代码或 Spring 配置,但我的问题的核心似乎是我要声明的路线:
@Component
public class EchoRoute extends RouteBuilder {
@Override
public void configure() throws Exception {
// "sync=true" seems necessary to return any response to the client at all
//
// "textline=true&autoAppendDelimiter=false" seem necessary to properly handle
// the socket input at newline-terminated strings, rather than processing
// input byte-by-byte
from("netty4:tcp://localhost:4321?sync=true&textline=true&autoAppendDelimiter=false")
// This line, and the corresponding `.header("incoming")` line below, are
// perhaps a bit dodgy. I'm assuming that all messages on the route
// from a given client socket are already effectively "correlated", and
// that messages from multiple client sockets are not inter-mingled
// here. So I'm basically wildcard-ing the correlation mechanism. If my
// assumption is wrong, then I'm not sure how to correlate by
// client socket.
.setHeader("incoming", constant(true))
// Taken from numerous examples I've seen in Camel books and website
// pages. Just concatenates the correlated messages until
// completion occurs.
.aggregate(new AggregationStrategy() {
@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange == null) {
return newExchange;
}
final String oldBody = oldExchange.getIn().getBody(String.class);
final String newBody = newExchange.getIn().getBody(String.class);
oldExchange.getIn().setBody(oldBody + newBody);
return oldExchange;
}
})
// See comment on "setHeader(...) above.
.header("incoming")
// In this initial testing, aggregation of a particular message is
// considered complete when the last line received is "EOM".
.completionPredicate(exchange -> {
final String body = exchange.getIn().getBody(String.class);
final boolean done = body.endsWith("EOM");
return done;
})
// This endpoint will eventually parse the aggregated message and
// perform logic on it. Right now, it just returning the input message
// with a prefix.
.to("bean:echoService");
}
}
当我启动服务器并4321
从单独的终端窗口远程登录到端口时,我可以在调试器中验证:
.completetionPredicate(...)
逻辑正在按预期在每一行输入上被调用,并且在一行输入之后,
echoService
端点正在按预期被调用。EOM
传递给端点的消息包含预期的聚合内容。
但是,有两个问题:
服务器将每行输入回显给客户端连接,而不是让端点确定响应内容。
服务器没有向客户端发送端点返回值。我将它记录到服务器控制台,否则它会被默默地丢弃。
关于我可能在这里遗漏的任何建议?期望的行为是路由将端点的返回值发送到客户端套接字,而只是端点的返回值。谢谢!