分组数据结构?

时间:2008-12-27 11:20:27

标签: networking packet

我正在设计一款游戏服务器,之前我从未做过这样的事情。我只是想知道数据包的良好结构是什么?如果重要,我正在使用TCP。这是一个例子,以及我现在考虑使用的内容:

(括号中的每个值都是一个字节)

[Packet length][Action ID][Number of Parameters]
[Parameter 1 data length as int][Parameter 1 data type][Parameter 1 data (multi byte)]
[Parameter 2 data length as int][Parameter 2 data type][Parameter 2 data (multi byte)]
[Parameter n data length as int][Parameter n data type][Parameter n data (multi byte)]

就像我说的那样,我之前从未做过这样的事情,所以我上面的内容可能是完整的公牛,这就是我要问的原因;)。另外,即使需要传递总包长度?

5 个答案:

答案 0 :(得分:3)

传递总包长度是个好主意。它可能需要多花费两个字节,但你可以偷看并等待套接字准备好在接收之前sip一个完整的数据包。这使代码更容易。

总的来说,我同意brazzy,语言提供的序列化机制比任何自制的都更受欢迎。

除此之外(我认为您使用的是没有序列化的C-ish语言),我会将数据包ID作为数据包数据结构的第一个数据。恕我直言,这是某种约定,因为结构的第一个数据成员始终位于0位置,任何结构都可以向下转换为该结构,识别其他匿名数据。

您的编译器可能生成也可能不生成压缩结构,但是这样您可以分配缓冲区,读取数据包然后根据第一个数据成员转换结构。如果你运气不好并且它不生成压缩结构,请确保为每个将从(显然是非目标)内存构造的结构有一个序列化方法。

Endiannes是一个因素,特别是在类C语言上。请务必明确说明数据包始终具有相同的字节顺序,或者您可以根据签名或其他内容识别不同的字节序。一个奇怪的事情非常酷:C#和.NET似乎总是在小端约定中保存数据,当你使用这里的文章中讨论的方式访问它们时。在SUN上将这样的应用程序移植到Mono时发现了这一点。很酷,但如果你有这个设置,你应该使用C#的序列化方法。

除此之外,您的设置看起来非常好!

答案 1 :(得分:3)

首先考虑一个更简单的基本包装:标签,长度,值(TLV)。您的基本数据包将如下所示:

[Tag] [Length] [Value]

标记是数据包标识符(如您的操作ID)。

长度是数据包长度。您可能需要这个来判断您是否拥有完整的数据包。它还可以让你弄清楚价值部分的持续时间。

包含实际数据。格式可以是任何东西。

在上面的例子中,值数据包含另一系列TLV结构(参数类型,长度,值)。您实际上不需要发送参数数量,因为您可以从数据长度处理数据并遍历数据。

正如其他人所说,我会把数据包ID(Tag)放在第一位。除非您有跨平台问题,否则我会考虑将您的应用程序的序列化对象包装在TLV中并通过这样的线路发送它。如果您犯了错误或想稍后更改,您始终可以创建具有不同结构的新标签。

有关TLV的详细信息,请参阅维基百科。

答案 2 :(得分:3)

为了避免重新发明轮子,任何序列化协议都适用于有线数据(例如XML,JSON),您可以考虑查看BEEP的基本协议框架。

BEEP在其常见问题解答文档中总结得很好,因为自从80年代初以来,经验丰富的应用程序协议设计人员使用的技巧就是“一种”最佳点击“专辑”。'

答案 3 :(得分:2)

没有理由做出像这样复杂的事情。我看到你有一个动作ID,所以我想会有一定数量的动作。

对于每个操作,您将定义一个数据结构,然后将这些值中的每一个放在结构中。要通过线路发送它,只需为结构中的每个元素分配sum(sizeof(struct.i))字节。所以你的数据包看起来像这样:

[action ID][item 1 (sizeof(item 1 bytes)][item 1 (sizeof(item 2 bytes)]...[item n (sizeof(item n bytes)]

这个想法是,您已经知道连接每一侧的每个变量的大小和类型,因此您不需要发送该信息。

对于字符串,您可以将它们以空终止形式抛出,然后当您'知道'根据您的数据包类型查找字符串时,开始阅读并查找空值。

-

另一种选择是使用'\ r \ n'来描述你的变量。这需要一些开销,你必须使用文本,而不是数字的二进制值。但是这样你就可以使用readline来读取每个变量。你的数据包看起来像这样

[action ID]
[item 1 (as text)]
...
[item n (as text)]

-

最后,简单地序列化对象并将它们传递到线路上也是一种很好的方法,只需要编写最少量的代码。请记住,您不希望过早地进行优化,也包括网络流量。如果事实证明你需要稍后挤出更多的性能,你可以回过头来找出一个更有效的机制。

并查看谷歌的protocol buffers,这应该是以平台中立的方式序列化数据的极快方式,有点像二进制XML,但没有嵌套元素。还有JSON,这是另一个平台中立编码。使用协议缓冲区或JSON意味着您不必担心如何对消息进行特定编码。

答案 4 :(得分:0)

您是否希望服务器支持使用不同语言编写的多个客户端?如果没有,可能没有必要准确指定结构;而是使用任何设施来序列化您的语言提供的数据,只是为了减少错误的可能性。

如果你确实需要这个结构是可移植的,那么上面看起来还可以,但在这种情况下你应该指定字节序和文本编码等内容。