作为我的网络安全和网络编程课程项目的一部分,我解决了这个问题并可以保证它不是一个巨大的数据包开关语句。该库名为跨平台网络,并且我将其建模于OSI模型的结构和如何将其输出为一个简单的对象序列化之上。该存储库在此处:
https://bitbucket.org/ptroen/crossplatformnetwork/src/master/
有无数的协议,例如NACK,HTTP,TCP,UDP,RTP,Multicast等,它们都通过C++元模板被调用。好的,那就是概括性的答案,现在让我深入一些,解释你如何解决这个问题以及为什么这个库可以帮助你,无论你是自己设计还是使用库。
首先,让我们谈谈一般的设计模式。要使它有良好的组织,你需要首先围绕它创建一些设计模式,作为解决问题的框架。对于我的C++模板,我最初围绕OSI模型(
https://en.wikipedia.org/wiki/OSI_model#Layer_7:_Application_layer)来进行设计,到传输层(此时变成了套接字)。回顾一下OSI:应用层:对最终用户的意义。即序列化或反序列化信号,从网络堆栈向上或向下传递;表示:来自应用程序和网络堆栈的数据独立性;会话:会话之间的对话;传输:运输数据包。
但是当你仔细看这些时,它们并不像设计模式,而更像围绕从A到B的传输创建的命名空间。因此,为了最终用户,我使用以下标准化的C++元模板设计了跨平台网络:
template <class TFlyWeightServerIncoming,//表示服务端传入负载的类。注意,FlyWeight是一个设计模式,是类型的联合,即将事物组合在一起。这是你打包传入对象的地方
class TFlyWeightServerOutgoing,//表示服务器不同类型的传出负载的类
class TServerSession,//代表如何将负载转换为会话层翻译的钩子类。关键是保持关注点分离(
https://en.wikipedia.org/wiki/Separation_of_concerns)
class TInitializationParameters>//表示服务器初始化的类(例如端口等)
两个示例:
https://bitbucket.org/ptroen/crossplatformnetwork/src/master/OSI/Transport/TCP/TCPTransport.h
https://bitbucket.org/ptroen/crossplatformnetwork/src/master/OSI/Transport/HTTP/HTTPTransport.h
每个协议可以像这样被调用:
OSI::Transport::Interface::ITransportInitializationParameters init_parameters
const size_t defaultTCPPort = 80
init_parameters.ParseServerArgs(&(*argv), argc, defaultTCPPort, defaultTCPPort)
OSI::Transport::TCP::TCP_ServerTransport<SampleProtocol::IncomingPayload<OSI::Transport::Interface::ITransportInitializationParameters>, SampleProtocol::OutgoingPayload<OSI::Transport::Interface::ITransportInitializationParameters>, SampleProtocol::SampleProtocolServerSession<OSI::Transport::Interface::ITransportInitializationParameters>, OSI::Transport::Interface::ITransportInitializationParameters> tcpTransport(init_parameters)
tcpTransport.RunServer()
引用:
https://bitbucket.org/ptroen/crossplatformnetwork/src/master/OSI/Application/Stub/TCPServer/main.cc
我在MVC的代码库中还有一个完整的MVC实现,但让我们回到你的问题。你提到:
“目前,我一直通过在头文件中开启数据包ID,然后有一大堆函数调用来处理每个数据包类型。”
“对于复杂的网络系统,这会导致一个庞大的switch语句,我真的不喜欢以这种方式处理它。我考虑的一种方法是使用处理程序类的映射。然后我可以将数据包传递给相关的类并处理传入的数据。我对此的问题是我需要某种方式将每个数据包处理程序注册到该映射中。通常,这意味着我需要创建类的静态副本,然后在构造函数中将其注册到中央数据包处理程序。虽然这样可以工作,但它似乎真的是一种不优雅和麻烦的处理方式。”
在跨平台网络中,添加新类型的方法如下:
1.定义服务器类型后,您只需创建传入和传出类型即可。处理它们的实际机制嵌入在传入对象类型中。其中的方法是ToString(),FromString(),size()和max_size()。这些方法处理保持应用程序层以下层级安全的安全问题。但是,现在您正在定义对象处理程序,因此需要将其转换为不同的对象类型的翻译代码。您至少需要在此对象中:
1.应用程序层的枚举对象类型列表。这可以简单地对它们进行编号。但是对于会话层之类的内容,请查看会话层问题(例如RTP具有诸如抖动和如何处理不完美连接之类的内容。即会话问题)。现在,您还可以从枚举切换到哈希/映射,但这只是解决了查找变量的问题的另一种方式。
2.定义序列化和反序列化对象(针对传入和传出类型)。
3.在序列化或反序列化后,将逻辑放置到适当的内部设计模式中以处理应用程序层。这可能是一个生成器、命令或策略,这取决于它的用例。在跨平台上,一些关注点由TServerSession层委托,另一些关注点由传入和传出类处理。这取决于关注点的分离。
4.解决性能问题。即它不是阻塞的(当您扩展并发用户时,这变得更加重要)。
5.解决安全问题(渗透测试)。
如果您感到好奇,可以查看我的API实现。它是一个单线程异步boost反应堆实现,当与像mimalloc(用于覆盖new delete)这样的东西结合使用时,可以获得非常好的性能。我轻松地在单个线程上测量了50k的连接。
是的,这一切都与良好的设计模式、分离关注点以及选择一个良好的模型来表示服务器设计有关。我认为OSI模型是适合这个的,这就是为什么我加入了跨平台网络以提供卓越的面向对象的网络。