我对网络协议的设计相当陌生,希望能对我的问题提出建议。
我的要求
设计--
Data Tunnel和Metadata Tunnel。优点
缺点
设计B
优点
缺点
我倾向于使用Design A,以便在“实时”保证上比在正确解码上更安全。但我想再和专家们核实一下我的想法。
我知道有数以百计的通信协议,但老实说,当我看随机协议文档时,它让我头晕目眩。毕竟,我的应用程序是相对轻量级的,因此滚动我自己的应用程序似乎更有意义。
顺便说一下,我使用Google Protobuf进行协议设计。我认为它的表现是实时准备的。
如有任何建议,将不胜感激。
发布于 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数据尽可能快/低延迟的其他一些建议:
send()-ing特定数据突发之后) --否则,大多数情况下您会得到200+毫秒不必要的延迟。setsockopt()具有SO_SNDBUF和SO_RCVBUF选项,使您的发送和接收套接字缓冲区尽可能大;这减少了缓冲区填充和数据包因缓冲区中没有可用空间而丢失的可能性。send()-ing),只需设置一个脏标志,指示需要发送该结构。然后,下一次套接字表明它已准备好写入,即序列化数据结构并将其发送到套接字的时间。好处是,如果您快速连续地接收到10个触发器事件,使用这种脏标志设计,您仍然只能跨一次发送最终版本的数据结构,而不是连续发送10次。第二个好处是,这限制了可以排队等待发送的数据的积压,从而减少了数据更新的平均延迟。recv()调用,该线程除了尽可能快地接收数据之外,只完成很少的工作,然后将其排队等待进一步的处理。这里的想法是尽量减少接收TCP套接字的传入数据缓冲区被填满的可能性,因为如果它变得满了,一些传入的TCP数据包可能会被丢弃,迫使TCP退换和重发,这将减缓传输速度。https://stackoverflow.com/questions/57815366
复制相似问题