我是发件人服务器发送的UDP多播数据(证券交易所数据)的客户端接收器。我不断收到udp组播数据包流,该流在6个小时内按顺序编号1到大约35,000,000,均匀发送。我需要确保在说到256个数据包之后定期处理N个数据包集之前,要接收到最多说N的 all 个数据包。即我需要可靠的UDP。
使用TCP重传来模仿可靠的UDP。如果丢失/未接收到任何udp数据包,则使用tcp协议通过指定所需的丢失数据包范围(开始编号,结束编号)来请求它。 发件人会记录所有到目前为止通过UDP多播发送的所有数据包(证券交易所数据)。因此,发件人将仅通过TCP重新发送接收方通过TCP特别请求的那些数据包编号。这就是接收方如何实现UDP可靠性。 UDP丢弃率非常小(小于0.001%),除了在一天中开始启动UDP多播时,在这种情况下,在实时传输时,所有先前发送的UDP数据包(从1到N)都需要在TCP上重新发送。的UDP多播数据包号N + 1开始被接收。)我无法请求发件人(证券交易所)更改其协议-它是固定的。
就CPU而言,实现此目标的有效算法是什么? 问题是速度BigOh。我可以使用几个嵌套的循环和方法来制作一个幼稚的算法,但不一定是最好的。
我正在考虑维护一个数字N,以确认我已收到UDP 数据包1到N,以及任何数据包号。 M,这不是下一个预期的数据包编号。 N + 1将被缓冲,例如256个数据包,然后将使用TCP请求丢失的数字。然后,正常的UDP接收将在TCP请求被填充后从最后一次确认的接收号码恢复。
示例: 假设接收方收到的UDP数据包的顺序为{1,2,3,6,7,8,9,10 ...} 在第3个数据包之后,下一个数据包是第6个数据包。第4至5个数据包丢失。 因此,使用TCP请求({4至5})请求丢失的数据包{4,5},并缓冲{6,7,8,9,10}。 10GBaseT LAN卡上有足够的空间来缓冲35,000,000个数据包。 因此:接收UDP {1,2,3},通过TCP请求{4,5}重新填充,继续接收UDP {6,7,8,9,10,...}
答案 0 :(得分:1)
我假设由于您正在使用多播,因此该数据将有多个接收者? (因为如果没有,您可能会改用单播)
因此,如果接收方可以选择请求重新传输未获得的数据包的TCP,则这意味着传输程序将需要在内存中保留最近发送的UDP数据包的副本。它收到一个重传请求,它将使请求的数据可用于重传。假设您要为每个数据包加一个唯一的ID,它可以将此数据存储在std::map
或std::unordered_map
或类似文件中,以便快速查找。
真正的问题是,发射机应该保留多少旧数据包?理想情况下,它将保留所有内容,因为您永远不知道给定的接收者可能错过了多少,并可能想要请求;但这需要无限的内存,所以这不是一个现实的选择。可能最好的办法是确定为此目的愿意占用多少RAM,并计算表中的总字节数,并在达到限制时开始丢弃最旧的数据包。从表中删除,以使其大小保持在限制之下。
我写了一个open-source library,它基本上使用了您所描述的技术(多播UDP + TCP从数据包丢失进行重传到TCP恢复),以便尽快在多个主机之间同步数据库。我在实施它时学到的一些知识包括:
如果可能的话,将数据消息打包到更大的数据包中,直至到达您正在传输的网络的MTU(例如,IPv4 /以太网为1388字节)。很小的数据包大小(如48字节/数据包)效率低下,因为固定大小的数据包报头在发送/接收的总数据中所占的比例更高。
仅在发送套接字指示已准备好写入时才尝试发送。 (即,不要以为您永远不会填满套接字的传出数据缓冲区;如果您的流量“突发”,您可能会在某个时候出现)
通过使UDP套接字的发送和接收缓冲区尽可能的大来使UDP数据包丢失最小化
通过在专用的高优先级线程中进行所有UDP接收(进而可以将接收到的UDP数据路由回普通优先级线程以进行进一步处理),进一步减少UDP数据包丢失,主要是为了避免允许接收的UDP套接字的传入数据缓冲区在可能的情况下溢出)
对于TCP重传部分,请记住,在最坏的情况下,TCP流有可能减慢到每秒近零字节,这对于确保客户端A的TCP性能不佳很重要。不会阻止与客户端B,C,D等之间的TCP通信。这可以通过非阻塞I / O和select()
(或poll()
或类似设备)或异步联网来完成,或通过多个线程;除非要实现每个套接字线程模型(否则可能也避免该模型,因为无限期阻塞inside-recv()的线程很难彻底关闭),否则请避免阻塞I / O。
考虑在什么情况下(如果有)客户端完全不接收特定数据包是可以接受的;在某些情况下可以吗?还是整个系统都必须停止工作,直到每个接收者都接收到该组中的每个数据包为止,而不管它可能要花多长时间?
如果您真的想花哨的话,可以考虑使用Forward Error Correction算法对数据包之间的数据进行编码,这样即使接收方从未接收到数据,接收方仍然可以对所有数据进行解码(最多一定百分比的数据包。这使得重新发送请求的可能性降低了,但代价是使所有数据包都稍大。