今天心血来潮,想写点东西,反哺一下。该文是我的处女作,是我几年前优化udp网络传输时的所得。
大家都知道,udp传输一般都是不断地、循环地取数据,然后发送,这就会造成了两个问题,第一:数据传送一窝蜂,如此,若网络带宽不够,则丢包,而要是对端接收处理不过来,则造成数据人为性丢失;第二:网络得不到充分的利用,有数据时一窝蜂,取数据时闲置等待。第一点应该很多人感同身受,深受其害,经常有人在论坛里抛出这个问题。而第二点,留意的人可能就不多了。一窝蜂的拥挤,必然会导致无数据的空闲,这个在抓包下就会露出原型。有时一秒钟内,前100毫秒在拼命地挤着往外跑,剩下900毫秒在等待新数据。如果你遇到这个问题了,那就接着往下看......
udp是不可靠传输,因此要实现可靠传输,必须有丢失重传机制,因此,在接收端就得在接收到数据后,把数据头返回,我们把它称为确认 ack,而发送端接收到这个确认,才释放数据内存,如果在规定时间内未接收到确认,则重传。如此,重传就实现了,现在开始使其极速平滑传输。
极速与平滑:传输速度取决于两个方面,一个是传输数据的长度,另一个是发送的频率。因此为了达到极速,我们就得从数据传输长度与发送频率来着手;而平滑,则是控制发送,使数据发送不至于一窝蜂,这个也是要在控制发送频率来着手。
我们需要两组丢包率阀值。
第一组packet_len_rate_min与packet_len_rate_max,用于判断发送数据包包长与丢包率的关系,这个关系,是由路径最小mtu引起的。在丢包率小于packet_len_rate_min时,我们增加包长,当丢包率大于packet_len_rate_max时我们减短包长度。当然包长度不小于576,不大于1500。而这个丢包率计算方法是:在单位时间内,丢失的包占总发包数的百分比。这样就实现了从数据包长度方面来动态调节发送速度。
第二组packet_send_rate_min与packet_send_rate_max,该组用于调控发送频率,使之实现极速与平滑。我们先来说下数据块的读取与发送,我们从源数据a上每次获取一等块数据,然后把数据放入到发送队列b里面,我们的发送线程再在b里获取数据并发送出去,然后等待,一直等待到接收到返回确认后,再去从数据源a读取数据,然后放入到发送队列b里。如此这般,一直循环。现在好了数据可以发送了,但速度不快,没关系,我们用手给它拨动下:在每接收到返回确认后,我们从源数据a里面读取两份数据,放入到发送队列b里面,由此,1变2,2变4,4变8......发送的速度是越来越快。但发送速度太快可能会带宽不够,或对端处理能力不足而丢包,此时,packet_send_rate_min与packet_send_rate_max就用上了。在变变变之后,当丢包率达到packet_send_rate_min时停止增速,而当大于packet_send_rate_max时,降低从数据源数获取的数据块数。
这样实现的发送频率非常均匀,而且在发送数据的时候,传输速度是由慢变快,自适应变化,达到极速。