面向对象的网络

问题描述 投票:16回答:7

我写了很多网络系统,并且很清楚网络是如何工作的。但是我总是最终拥有一个数据包接收功能,这是一个巨大的switch语句。这开始转向我。我宁愿采用一种优雅的面向对象的优雅方式来处理接收数据包,但每当我尝试提出一个好的解决方案时,我总会遇到问题。

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

目前我一直在通过打开标头中的数据包ID然后拥有一大堆处理每种数据包类型的函数调用来实现这一目标。对于复杂的网络系统,这会产生一个单一的switch语句,我真的不喜欢这样处理它。我考虑过的一种方法是使用处理程序类的映射。然后我可以将数据包传递给相关的类并处理传入的数据。我遇到的问题是我需要一些方法来使用地图“注册”每个数据包处理程序。这意味着,通常,我需要创建类的静态副本,然后在构造函数中将其注册到中央数据包处理程序。虽然这有效,但它看起来似乎是处理它的一种不雅和繁琐的方式。

编辑:同样,理想的是拥有一个兼顾两种方式的漂亮系统。即一种类结构,它容易处理发送与接收它们相同的数据包类型(显然通过不同的功能)。

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

如果我没有很好地描述我的问题而道歉,因为我无法很好地描述它也是我从未设法提出解决方案的原因。

c++ oop networking packets
7个回答
5
投票

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

至于班级结构。有些图书馆已经完成了这项工作:Available Game network protocol definition languages and code generation。例如。 Google's Protocol Buffer似乎很有希望。它为协议描述中的每条消息生成一个包含getter,setter,serialization和deserialized例程的存储类。协议描述语言或多或少看起来很丰富。


1
投票

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


1
投票

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

虽然std::map很好,但我最终使用静态表。 std::map不能静态初始化为常量表。它必须在运行时加载。表(结构数组)可以声明为数据并在编译时初始化。我没有遇到过线性搜索成为瓶颈的表格。通常表大小足够小,以至于二进制搜索的开销比线性搜索慢。

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


1
投票

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

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的内置序列化模块pickle;客户:

import pickle
obj = {1: "test", 2: 138, 3: ("foo", "bar")}
clientsock.send(pickle.dumps(obj))

服务器:

>>> import pickle
>>> r = pickle.loads(rsock.recv(1000))
>>> r
{1: 'test', 2: 138, 3: ('foo', 'bar')}

所以,正如你所看到的,我只是发送了一个链接本地的Python对象。这不是OOP吗?

我认为序列化的唯一可能替代方法是维护bimapID⇔类。这看起来真的不可避免。


1
投票

您希望继续使用相同的分组网络协议,但在编程中将其转换为Object,对吗?

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

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


1
投票

处理此问题的更多OO方法是使用状态模式构建状态机。

处理传入的原始数据正在解析状态机提供优雅解决方案的位置(您必须在优雅和性能之间进行选择)

您有一个要处理的数据缓冲区,每个状态都有一个句柄缓冲区方法,用于解析和处理缓冲区的部分(如果已经可以),并根据内容设置下一个状态。

如果你想要提高性能,你仍然可以使用状态机,但忽略了OO部分。


1
投票

我会使用Flatbuffers和/或Cap’n Proto代码生成器。

© www.soinside.com 2019 - 2024. All rights reserved.