c# - 封装网络协议(protocol)

标签 c# networking

我正在开发一个应用程序,它接收原始二进制消息(非常简单,第一个字节是消息类型,其余字节是有效负载),然后用它做一些事情。我想要完成的事情是确保网络服务从应用程序的其余部分中抽象出来,以允许不时地修改协议(protocol),而不会过多地影响应用程序的其余部分。 应用程序的上下文是一个非常简单的客户端-服务器游戏,我现在正在为此做客户端工作。

虽然我现在有点挣扎。我需要找到一种优雅的方式来将连接放入某种翻译器/适配器服务中,它返回漂亮的对象(我认为)。这些对象将被放入队列中,等待应用程序的其余部分使用。我面临的问题或多或少是这个构造(伪代码):

假设每条消息都是 20 个字节,那么我可以处理为每 20 个字节调用此函数:

public Message GetMessage(byte[] buffer)
{
  switch(buffer[0])
  {
     case 1:
       return Message1(...);
     case 2:
       return Message2(...);
     .....

     case n:
       return MessageN(...);
  }
}

显然,我会针对这种情况使用枚举或常量,但这不是困扰我的事情。 事情是这样的。我想我有大约 50 种消息类型,这意味着我将获得包含 50 个案例的 switch 语句。我真的想不出一个合适的方法来将它分成更小的部分,这将导致一个巨大的、容易出错的方法。我想知道是否有任何模式可以使这更容易,因为我找不到任何模式。

提前感谢您的输入!

最佳答案

我有一些 Java 代码可以执行此操作。希望您可以轻松地转换为 C#。本质上,我有一个 messageMap 集合:

private final Map<Byte, Class<? extends Message>> messageMap;

这是从消息 ID 到它们对应的 Message 类的映射。我为每种不同的消息类型调用一次 addMessage:

public void addMessage(int id, Class<? extends Message> messageClass) {
    messageMap.put((byte) id, messageClass);
}

然后当消息到达时,我从网络上读取消息 ID,查找我需要在 messageMap 中实例化的 Message 类,然后使用反射创建一个该类的实例。

Class<? extends Message> messageClass = messageMap.get(id);
Message                  message      = messageClass.newInstance();

此处 newInstance() 调用默认构造函数。

我已经在具有不同消息的多个应用程序中使用了这种通用消息处理代码。每个人都有一个漂亮、简单的代码块来注册不同的消息,如下所示:

// Messages that we can send to the client.
addOutgoingMessage(0, HeartbeatMessage.class);
addOutgoingMessage(1, BeginMessage    .class);
addOutgoingMessage(2, CancelMessage   .class);

// Messages that the client can send.
addIgnoredMessage (0, HeartbeatMessage.class);
addIncomingMessage(1, StatusMessage   .class, statusMessageHandler);
addIncomingMessage(2, ProgressMessage .class, progressMessageHandler);
addIncomingMessage(3, OutputMessage   .class, outputMessageHandler);
addIncomingMessage(4, FinishedMessage .class, finishedMessageHandler);
addIncomingMessage(5, CancelledMessage.class, cancelledMessageHandler);
addIncomingMessage(6, ErrorMessage    .class, errorMessageHandler);

关于c# - 封装网络协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1018564/

相关文章:

javascript - 如何获取用户控件下拉列表的ClientID

c# - 如何使用 OR/And 运算符组合 N 个表达式树

c# - 通过解码 "*.itemdata-ms"二进制数据文件自定义Windows 8.1 StartScreen (Windows 8.1, StartScreen, C#)

c++ - 这个 boost-asio UDP 广播代码应该如何只与本地主机一起工作?

networking - 当多台计算机具有相同的 IP 地址时,如何以编程方式连接到其中一台?

java - 本地PC服务器和android模拟器之间的Socket连接

c# - 填充特定形状 - 带颜色的 ShapeStyle C# PowerPoint OpenXML

c# - 有没有办法截取用户 Windows 桌面的屏幕截图?

http - 在 Charles 中看不到网络请求

python - 如何识别内网电脑?