1

我正在尝试使用 Apache Camel 来实现 TCP 游戏服务器。它将接受来自多个人类或机器人玩家的双向、同步 telnet 或 SSH 连接。

通信“协议”有点粗糙,并且基于早期版本中已经存在的遗留基础设施。基本上,客户端和服务器通过套接字交换 I/O(每个客户端一个连接)。

通常,这由单行命令字符串或单行响应字符串组成。但是,在某些情况下,输入或输出可以跨越多个换行符,然后才被视为“完整”并准备好接受对方的响应。所以我的计划是:

  1. 使用 Spring Boot 和 Apache Camel 创建 TCP 套接字服务器,并使用后者的“Netty4”组件。

  2. 使用聚合从套接字连接收集传入的文本行。根据检测到的输入类型,将它们汇总为一行或多行的消息。

  3. 将生成的消息传递给端点,端点解析输入并将适当的响应返回给套接字。

我可以显示任何其他代码或 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从单独的终端窗口远程登录到端口时,我可以在调试器中验证:

  1. .completetionPredicate(...)逻辑正在按预期在每一行输入上被调用,并且

  2. 在一行输入之后,echoService端点正在按预期被调用。EOM传递给端点的消息包含预期的聚合内容。

但是,有两个问题:

  1. 服务器将每行输入回显给客户端连接,而不是让端点确定响应内容。

  2. 服务器没有向客户端发送端点返回值。我将它记录到服务器控制台,否则它会被默默地丢弃。

关于我可能在这里遗漏的任何建议?期望的行为是路由将端点的返回值发送到客户端套接字,而只是端点的返回值。谢谢!

4

0 回答 0