Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 面向对象网络_C++_Oop_Networking_Packets - Fatal编程技术网

C++ 面向对象网络

C++ 面向对象网络,c++,oop,networking,packets,C++,Oop,Networking,Packets,我写过很多网络系统,对网络的工作原理有很好的了解。然而,我总是有一个数据包接收函数,它是一个巨大的交换语句。这开始影响到我了。我宁愿用一种优雅的面向对象的方法来处理接收数据包,但每次我试图想出一个好的解决方案,结果总是落空 例如,假设您有一个网络服务器。它只是在那里等待回应。一个数据包进来,服务器需要验证该数据包,然后决定如何处理它 目前,我一直在通过在报头中切换数据包id,然后进行大量处理每种数据包类型的函数调用来实现这一点。对于复杂的网络系统,这会导致一个单片开关语句,我真的不喜欢这样处理它

我写过很多网络系统,对网络的工作原理有很好的了解。然而,我总是有一个数据包接收函数,它是一个巨大的交换语句。这开始影响到我了。我宁愿用一种优雅的面向对象的方法来处理接收数据包,但每次我试图想出一个好的解决方案,结果总是落空

例如,假设您有一个网络服务器。它只是在那里等待回应。一个数据包进来,服务器需要验证该数据包,然后决定如何处理它

目前,我一直在通过在报头中切换数据包id,然后进行大量处理每种数据包类型的函数调用来实现这一点。对于复杂的网络系统,这会导致一个单片开关语句,我真的不喜欢这样处理它。我考虑过的一种方法是使用处理程序类的映射。然后我可以将数据包传递给相关类并处理传入的数据。我遇到的问题是,我需要某种方法用map“注册”每个数据包处理程序。这意味着,通常,我需要创建类的静态副本,然后在构造函数中向中央数据包处理程序注册它。虽然这是可行的,但它确实似乎是一种不雅观的、微妙的处理方式

编辑:同样,拥有一个双向运行的好系统也是理想的选择。ie是一种类结构,可以轻松处理发送和接收相同的数据包类型(显然是通过不同的函数)

有人能告诉我一种更好的方法来处理传入的数据包吗?链接和有用的信息非常感谢


如果我没有很好地描述我的问题,我表示歉意,因为我无法很好地描述它,这也是我从未想出解决方案的原因。

处理程序实例的映射几乎是处理它的最佳方式。没什么不雅观的。

以我的经验,表驱动解析是最有效的方法

虽然
std::map
很好,但我最终还是使用了静态表。无法将
std::map
静态初始化为常量表。它必须在运行时加载。表(结构数组)可以声明为数据并在编译时初始化。在线性搜索是瓶颈的情况下,我还没有遇到足够大的表。通常,表的大小足够小,因此二进制搜索的开销比线性搜索慢


为了获得高性能,我将使用消息数据作为表的索引

当你在进行面向对象编程时,你试图把每一件事都表示成一个对象,对吗?因此,您的协议消息也成为对象;您可能会有一个基类
YourProtocolMessageBase
,它将封装任何消息的行为,并从中继承多态专用消息。然后,您只需要一种方法将每条消息(即每个
YourProtocolMessageBase
实例)转换为一个字节字符串,以及一种反向转换的方法。这种方法称为技术;存在一些基于元编程的方法

Python中的快速示例:

from socket import *
sock = socket(AF_INET6, SOCK_STREAM)
sock.bind(("localhost", 1234))
rsock, addr = sock.accept()
服务器块,为客户端启动另一个实例:

from socket import *
clientsock = socket(AF_INET6, SOCK_STREAM)
clientsock.connect(("localhost", 1234))
现在使用Python的内置序列化模块;客户:

服务器:

>>> import pickle
>>> r = pickle.loads(rsock.recv(1000))
>>> r
{1: 'test', 2: 138, 3: ('foo', 'bar')}
如您所见,我刚刚通过本地链接发送了一个Python对象。这不是很糟糕吗


我认为序列化的唯一可能的替代方法是维护bimap ID⇔ 上课。这看起来确实是不可避免的。

关于处理数据包类型的方法:对我来说,map是最好的。但是,我会使用普通数组(或向量)而不是贴图。如果从0开始按顺序枚举数据包类型,则访问时间将保持不变


至于阶级结构。有些库已执行此作业:。似乎很有希望。它为协议描述中的每条消息生成一个包含getter、setter、序列化和反序列化例程的存储类。协议描述语言看起来或多或少很丰富。

您希望继续使用相同的数据包网络协议,但在编程中将其转换为对象,对吗

有几种协议允许您将数据视为编程对象,但您似乎不想更改协议,只想更改在应用程序中处理数据的方式


这些数据包是否带有“标记”或元数据或任何允许您映射到特定对象类的“id”或“数据类型”?如果是这样,您可以创建一个存储id和匹配类的数组,并生成一个对象。

一个更面向对象的处理方法是使用状态模式构建一个状态机

处理传入的原始数据就是解析,其中状态机提供了一个优雅的解决方案(您必须在优雅和性能之间进行选择)

您有一个要处理的数据缓冲区,每个状态都有一个handlebuffer方法,该方法解析和处理缓冲区中的他的部分(如果可能的话),并根据内容设置下一个状态


如果您想提高性能,您仍然可以使用状态机,但不使用OO部分。

我将使用和/或代码生成器。

您不需要处理程序类的静态副本。您可以在构造函数中传递实例。不过,这并没有多大改善(@Martinho:但这意味着我必须在某个地方实例化每个可能的类。如果我在类的实现文件中声明了自身的静态版本,那么构造函数就会自动被调用。你看到了吗?@belisarius:没有,我也不能。是否有到该论文的直接链接?我在Citeser或google sch上找不到它奥拉尔:(@Goz-Nope.但是有更多的是来自同一个作者,但绝对是血腥的fiddly;)fiddly有一个固定的数量,在这种情况下,它只是一个如何以及在哪里传播的问题。是的,它确实有一个包id。我看不出你是如何传播的
>>> import pickle
>>> r = pickle.loads(rsock.recv(1000))
>>> r
{1: 'test', 2: 138, 3: ('foo', 'bar')}