建立初始套接字连接后如何构建 TcpListener 和 TcpClient 之间的通信

How to structure communication between TcpListener and TcpClient after initial socket connection is made

所以这对于网络编程人员来说可能非常简单,但我对此有点困惑。让我试着问一个用法的例子。

假设我要创建一个聊天服务器,客户端可以使用用户名加入。没有帐户或密码。只是用户名。

我有一个有效的 Echo Server 示例 运行,它使用异步调用,所以一切都很好。现在我需要定义一些客户端和服务器之间的消息处理。

假设客户端现在已连接并且它想要获取已连接用户的列表。我该怎么做?

我的想法是创建一个名为 BeginGetConnectedUsers 的函数,它将向服务器发送消息。然后服务器将回复用户列表,但因为我使用的是异步调用,所以我现在让我的接受代码查看消息并确定它是来自 BeginGetConnectedUsers 的回复,因此它将数据发送到 EndGetConnectedUsers .

但我不知道这样做是否是个好方法? 但是对于这种设计,我还必须将每个 BeginGet 函数与 EndGet 函数配对。使用 async await 样式可以使这更具可读性,但是这可能也不是更可取的。

当客户端和服务器必须开始交换所有有趣的数据时,我对如何构建客户端和服务器之间的以下通信没有经验...

还有建议?看的地方?我所有 google 搜索包括工作 TCPLISTENER 都会向我展示 Echo 服务器的示例,我已经知道如何做到这一点。

这里有很多可能的实现。 我会实施策略模式或控制器模式。其他选项是状态机(确定性自动机),甚至是简单而大的开关盒。

所以基本上你只有一个函数来接收来自线路的消息。 所有消息实现相同的接口可能是

IMessage<T>
{
    string Type {get;set;}
    T Data {get;set;}
}

因此,当您收到消息时,您可以使用类型 属性 将 T 数据路由到您想要的实际方法。 在使用控制器的简单实现中,您使用指示要管理的消息类型的属性对控制器方法进行注释:

class Controller
{
    [Messagetype("GetConnectedUsersResponse")]
    Response GetConnectedUsers(IEnumerable<User> users)
    {
        //...
    }

    [Messagetype("AnothermessageType")]
    Response OtherStuffToDo(....)
    {
        //...
    }
}

当您收到消息时,通过使用一些简单的反射,您可以动态调用具有匹配消息类型属性的方法。

如果您不喜欢反射,另一个选择(在许多其他文档中)是使用策略模式 因此,例如,您可以在 IoC 容器中按键注册一些消息处理程序。 所有 hadlers 都实现一个函数让我们说

interface MessageHandler<T>
{
    Response Handle(T Data);
}

当您收到消息时,您只需使用您最喜欢的 IoC 容器解析处理程序(按名称解析最近被认为是一种 atipattern,因此请谨慎对待)

var handler = container.resolve(message.Type);
var response = handler.handle(message.Data);

在这两种实现中,你应该定义你如何回应(如果你这样做)并调整 "Response" return 类型(可能你只是没有回应所以它是无效的)