【问题标题】:How to implement binary TCP protocol如何实现二进制 TCP 协议
【发布时间】:2015-08-16 10:37:20
【问题描述】:

我过去创建了许多 TCP 客户端/服务器应用程序,它们总是使用非常简单的基于文本的协议,要么是由换行符分隔的文本消息,要么是 Xml 流。

现在我正在为游戏服务器创建一个简单的协议,该协议主要用于交换 Vector 信息并与客户端处理一些简单的 RPC 调用。因为它将成为一个游戏服务器,我真的希望它超级快速和轻量级。出于这个原因,我决定将其实现为二进制协议(有关我的意思的更多信息,请参阅Are binary protocols dead?)。

我有一个粗略的想法,但在我开始研究它之前,我想确认这种方法确实有效,如果没有更好的常用方法。我过去从未实现过二进制 TCP 协议。

我将在“信息包”中发送所有信息,我称之为“数据报”。协议中的另一个重要常量是以字节为单位的浮点数大小,我称之为BLOCK_SIZE。我将使用多种语言(客户端是 C#,而服务器是 C++),我需要确保所有平台(x86、x64)在数据报中具有相同大小的数字。

服务器发送给客户端的第一个信息将是一个单字节 (sizeof(char)),其中包含 BLOCK_SIZE 的值,只是为了确保浮点数(我使用的是 double,因为它对我来说足够大目的)将在服务器和客户端上占用相同数量的字节。然后是“数据报”流,直到通信通道结束。

数据报的布局是:

Size in bytes / name                  Description
BLOCK_SIZE / type            Type of datagram (for internal purposes I need to figure out what I am actually going to process - I could probably create header instead that would describe it in details, but for my purposes one `double` can contain all possible types I will use)
unsigned BLOCK_SIZE / size   Length of datagram - number of bytes that will follow. I just hope I will never need to send a single datagram that would be bigger tham maximum value of unsigned double :P
size / data                  Data that are contained within datagram, I will process them based on what `type` they will be.

我想,为了接收,我总是会创建一个缓冲区,就像任何一方宣布的 size 一样大,并不断将数据推入其中,除非我得到所有数据。然后我就可以开始处理另一个数据报了。

我相信只要客户端和服务器始终发送正确的数据,没有一个字节错误、多余或丢失,这应该可以工作。我不知道 TCP 是否足够可靠,或者我是否还需要实现一些错误检查。我不知道怎么做。

我只需要传输大量的浮点数数组,最后是一些非常简单的字符串,但我并不需要马上关心这些。这是一个正确的方法还是我应该以不同的方式来做?

【问题讨论】:

  • 在重新发明轮子之前,也许 Protocol Buffers 是您的解决方案? developers.google.com/protocol-buffers
  • 避免车轮改造是我在这里问的原因之一:P
  • 您的标题给人的印象是您想创建自己的协议...

标签: networking tcp


【解决方案1】:

如果要使用 TCP 传输,请不要使用“数据报”一词;数据报通常与 UDP 传输相关联。

TCP 是可靠的,那么您不需要额外的 CRC 或类似的东西。

您可以实现即一个非常简单的二进制流协议,其中 每个数据单元前加 2 个字节;第一个表示它的类,第二个表示它的长度。

                   class     length
unsigned byte        1          1
         byte        2          1
unsigned short       3          2
         short       4          2
unsigned int         5          4
         int         6          4
        ...

array unsigned byte  1          1 * #elements 
array          byte  2          1 * #elements
array unsigned short 3          2 * #elements 
array          short 4          2 * #elements
array unsigned int   5          4 * #elements 
array          int   6          4 * #elements
        ...

length 变量(一个字节)的表示将数据元素的总大小限制为 255 个字节 class 变量(一个字节)的表示将类的总数限制为 255

请记住,使用 TCP 时,您必须处理与传输数据单元大小无关的数据“流”。您不应该对接收到的数据包的大小做出假设;一个数据单元可以很好地拆分为多个 TCP 数据包,即使它适合一个单独的数据包

即序列 0x01-0x01-0x33 是一个可以表示的数据单元,即 ASCII 字符“3”

您可能认为开销太大,但传输单个字节是最坏的情况,当数据单元变大时开销会变小。还要考虑这是不依赖于预定义的更高级别数据结构的代价。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    相关资源
    最近更新 更多