如何分离TCP套接字消息

6
我曾经尝试使用异步TCP套接字消息在两个程序之间传递数据、数字和/或文本。我的做法是在每条消息的开头使用一个关键字,然后用“|”字符分隔值。因此,一条消息可能看起来像这样:
"DATA|490|40517.9328222222|1|6|11345|11347|11344|11345|106|40517.8494212963"
我将读取缓冲区大小设置为1024,因为大多数消息都不超过这个长度。但是有时候我可能会快速发送许多短消息,其中几个加起来不到1024个字符,那么它们似乎会一次性读取。如果我发送的消息超过1024个字符,则会被分割。因此,我正在寻求如何处理这种情况的建议。我应该使用一些特殊字符来开始和/或结束每条消息吗?希望您能给出一些建议。
6个回答

7
最简单的方法是在每个消息的开头发送消息长度,以一种能够适用于小端和大端硬件的序列化方式进行序列化。这样做还可以帮助接收者有效地预分配其接收缓冲区。

谢谢!你所说的序列化是什么意思?它适用于标准的Windows操作PC吗?根据您最后的评论,这是否意味着我应该根据接收到的消息更改缓冲区大小?这将如何工作...由于在读取消息之前无法确定消息的长度,我不太明白您的意思。顺便问一下,将消息拆分为多个部分是否有意义,或者对性能没有任何影响?每200毫秒大小为50个字符的消息,很少会有一个50,000-400,000个字符的消息。 - bretddog
2
序列化只是指“输出为字符串”。@terminus的建议是一种合理的方法 - 将消息长度转换为固定长度的字符串,以便在接收端轻松地将其转换回“unsigned int”。您可以首先请求读取那么多字节到固定大小的缓冲区中,然后分配一个缓冲区来接收其余的消息。不要在发送端拆分消息 - TCP/IP堆栈将执行任何所需的数据包处理。 - Steve Townsend

4

最简单的方法是在数据包开头发送消息的大小。这样你就知道要读取多少数据了。因此,它看起来像:

00015MESSAGE|1|2 ...

size字段具有固定大小非常重要。

您还可以将此大小字段设置为二进制,但似乎您正在发送纯文本,因此使用这种方式可以获得可读性良好的大小字段。


3

有几种方法:

  1. 在每个消息前加上长度单词。

  2. 使用STX/ETX样式包装每个消息,以便您可以看到它何时开始和结束。这需要转义数据中出现的ETX字节,而这又需要转义ESC字节。

  3. 自描述协议,例如XML或基于类型长度值的协议。


OP已经必须转义出现在数据中的|字符,因此这可能不是一个负担。 - caf

1

协议是一切。对于我的聊天应用程序,我使用参数协议,就像运行时一样。

shutdown.exe -s -f -t 30

但是对于套接字,我使用这个

join John%20Doe            ' %20 for space
msg This%20Is%20a%20test   ' again %20 for space

这样做就不用担心您的数据是否以异步方式发送 :D 希望这可以帮到您


0

你可以通过在消息中填充唯一的字节(例如ASCII中不存在的255)来解决这个问题,使其达到缓冲区大小,并在接收端取消填充。

对我来说,这不是一个很好的和聪明的解决方法,但它确实有效。

或者你可以尝试在每个数据包的开头发送整个数据包的长度,这比填充技术更具挑战性,当正确执行时效率更高。合并后的数据包将看起来像这样(方案):

05|.....02|..03|...

0
TAR的处理方式是使用固定大小的块。 TAR中的每个块都是512字节,文件(消息)可以完全包含在一个块中。如果不是,则前512字节包括一个标题,指定需要读取多少个附加块以获取该文件(消息)。
Tar显然不是TCP应用程序,但它具有类似的数据解析或处理要求。
此外,您的大小小于512字节,但可能有意义包括64字节块、128字节块或其他大小的块,并将所有数据分批发送。虽然会因为“盒子大小”的开销而失去效率,但您可能会在数据处理算法的效率和简单性方面获得收益。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接