如何弥合从 Netty ChannelInboundHandler 到 kotlinx 协程调度程序的差距?

Eid*_*lon 5 netty kotlin kotlinx.coroutines

我有一个多路复用的应用程序协议,我已经实现了管道阶段,用于在两个方向上处理代表协议中每种类型消息的 Kotlin 数据类。没有正式的请求-响应模式;客户端和服务器可以在套接字生命周期内的任何时刻向对方发送消息。

在协议中,有一个约束,即对于任何连接的客户端,消息都是串行处理的。也就是说,当服务器收到来自客户端的消息时,在完全处理完前一条消息之前,它无法处理来自客户端的下一条消息。相同的规则适用于处理来自服务器的消息的客户端。这或多或少就是 Netty 中处理通道管道的方式;给定的管道阶段一次只能处理一件事。通过在新的执行器组上设置阻塞管道阶段,这很容易编码。

但是,我想为客户端可能以挂起函数的形式发送的每种类型的消息编写处理程序,因为我的服务器响应客户端消息可能执行的操作范围非常广泛,并且可能涉及联系其他服务器或数据库,并且一组消息类型还可以在处理期间内部锁定部分服务器状态,以排除其他并发连接的客户端。所以我需要一种从 Channel 管道的尾端桥接到协程上下文的方法,使得管道阶段被“阻止”继续处理消息,但不会阻止此阶段其他通道管道的处理,并且无需为每个套接字创建单线程事件执行器。

我曾想过使用 Netty 中的单独调度程序和事件循环来表示每个客户端会话的处理,使用一个 actor 来表示每个客户端会话,这样接收到的消息将发送到 actor 的邮箱通道,并且协程按接收顺序处理它们,并且我可以取消演员并在其取消时关闭SocketChannel,反之亦然。但这相当丑陋,而且不符合 Netty 的精神。

tl;dr 我想知道,实现将挂起函数与其执行器组干净地集成的管道阶段的最佳方法是什么?