首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >实时数据加元数据的TCP通信协议

实时数据加元数据的TCP通信协议
EN

Stack Overflow用户
提问于 2019-09-06 03:33:33
回答 1查看 800关注 0票数 0

我对网络协议的设计相当陌生,希望能对我的问题提出建议。

我的要求

  1. 我需要将实时数据从TCP套接字客户端流到服务器。我在这里别无选择,
  2. 数据需要在服务器端正确解码元数据描述符。此描述符可以代表客户端用户在运行时进行更改。
  3. 我需要发送偶尔的控制命令从客户端到服务器的数据操作。

设计--

  • 设置两对套接字服务器和客户端,一对用于需求1,另一对用于需求2和3;现在称它们为Data TunnelMetadata Tunnel

优点

  • 概念清晰,易于在实现中分离元数据和数据模块。
  • 实时数据,即#1,可以作为字节发送,不需要额外的数据封装。

缺点

  • 两个隧道之间需要同步,以避免由于控制更改而导致的解码错误或故障。
  • 每个套接字-客户端对可能需要两个线程,以避免阻塞应用程序的主线程:每个隧道有一个线程。

设计B

  • 只使用一条隧道。
  • 分别为实时数据和元数据设计至少两个分组数据结构。实时数据包将包括其解释。
  • 让数据和元数据共享唯一的隧道。

优点

  • 每个实时数据包都与元数据捆绑在一起,并保证正确解码。
  • 只使用一个线程。

缺点

  • 更复杂的接收机数据处理实现,例如,必须在接收数据包时区分数据和元数据。
  • 单一隧道的交通更加繁忙。我打赌控制信息不会阻碍实时数据的消耗,但我真的不知道这一点。

我倾向于使用Design A,以便在“实时”保证上比在正确解码上更安全。但我想再和专家们核实一下我的想法。

我知道有数以百计的通信协议,但老实说,当我看随机协议文档时,它让我头晕目眩。毕竟,我的应用程序是相对轻量级的,因此滚动我自己的应用程序似乎更有意义。

顺便说一下,我使用Google Protobuf进行协议设计。我认为它的表现是实时准备的。

如有任何建议,将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-06 04:49:44

正如@RonMaupin在注释中提到的那样,TCP和“实时”并不是特别兼容的,因为TCP优先考虑的是“正确地获得那里的字节”,而不是“在特定的时间范围内获得字节”。

尽管如此,您可以使用TCP实现的是“尽可能快地获得字节”,只要您能够接受这样一个事实:在某些情况下(例如,正在丢弃大量数据包的网络),“尽可能快”可能不是那么快。

关于要使用多少TCP流,与做出该决定相关的TCP的质量是,TCP流总是强制按顺序/FIFO传递该流中的字节。也就是说,所有send()到TCP套接字的字节都将按照接收程序的确切顺序排列--这是一种可以对您有效的行为,也可以是对您不利的行为,因此您希望程序的设计方式能够为您工作。特别是,当决定是否使用一个或多个TCP连接时,问问自己:“我发送的数据是否需要按照发送的相同顺序接收,或者这不重要?”如果严格的FIFO排序是重要的,而不是单一的TCP流是可行的;OTOH,如果您有两种类型的数据,并且B类型的数据在逻辑上独立于类型-A数据,那么您可以考虑将类型-B数据赋予它自己的单独TCP流,这样丢弃的数据包-A-数据不会减慢B-数据的传输速度。

无论如何,您至少需要一些最小的协议/帧(例如,在每个数据消息之前至少要有消息类型和消息大小的头字段),这样接收方就不必猜测它正在接收的字节的含义。(即使您一开始不需要它们,您也希望在第二个版本中使用它们来帮助保持与以前版本的协议的向后兼容性)

关于使TCP数据尽可能快/低延迟的其他一些建议:

  1. 禁用Nagle的算法(永久地或至少在完成send()-ing特定数据突发之后) --否则,大多数情况下您会得到200+毫秒不必要的延迟。
  2. 假设您的程序运行在具有大量内存的平台上,setsockopt()具有SO_SNDBUFSO_RCVBUF选项,使您的发送和接收套接字缓冲区尽可能大;这减少了缓冲区填充和数据包因缓冲区中没有可用空间而丢失的可能性。
  3. 如果可能的话,设计您的发送算法,只在最后可能的时刻生成要发送的数据,而不是预先排队等待发送的大量数据。例如,如果(由于某些触发事件)您的代码决定需要通过TCP套接字尽快发送特定数据结构的当前状态,而不是立即序列化数据结构和排队(和/或send()-ing),只需设置一个脏标志,指示需要发送该结构。然后,下一次套接字表明它已准备好写入,即序列化数据结构并将其发送到套接字的时间。好处是,如果您快速连续地接收到10个触发器事件,使用这种脏标志设计,您仍然只能跨一次发送最终版本的数据结构,而不是连续发送10次。第二个好处是,这限制了可以排队等待发送的数据的积压,从而减少了数据更新的平均延迟。
  4. 在接收端,让一个专用的、高优先级的线程在一个紧密的循环中完成recv()调用,该线程除了尽可能快地接收数据之外,只完成很少的工作,然后将其排队等待进一步的处理。这里的想法是尽量减少接收TCP套接字的传入数据缓冲区被填满的可能性,因为如果它变得满了,一些传入的TCP数据包可能会被丢弃,迫使TCP退换和重发,这将减缓传输速度。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57815366

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档