如何实现二进制TCP协议

时间:2015-06-02 14:49:13

标签: networking tcp

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

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

我对如何做到这一点有一个粗略的想法,但在我开始研究之前,我想确认这种方法实际上是可行的,如果没有更好的,常用的方法。我以前从未实现二进制TCP协议。

我将在"信息包中发送所有信息"我刚刚打电话给#34;数据报"。协议中另​​一个重要的常量是浮点数的大小,以字节为单位,我只称之为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是否足够可靠,或者我是否还需要执行一些错误检查。我不知道怎么做。

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

1 个答案:

答案 0 :(得分: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
        ...

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

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

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

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