live555推流----局域网延迟的分析

============20191212--追加---------以下主要追究发送比较大的网络数据时多次调用 系统调用send而产生的耗时问题,不过对于实际上传输音视频实时流的使用场景,往往数据不会这么大,延迟的性能瓶颈主要不在于此========================

最近在做局域网投屏相关,发现使用vlc做推流和接受,延迟过大(1s以上),改用live555推流和接受,延迟还是过大,局域网中还打不到<200ms的延迟。于是乎研究了好一阵子live555源代码,也没有发现其代码层面故意的休眠的情况出现,苦思冥想数日,不得解,直到这个阳光明媚的周六,突然就想到一个方法,排除live555代码,有没有一个方法来直接了当地验证网络本来就性能不够呢,虽然说是局域网,似乎这个怀疑本生就不太然人觉得可靠。 周六就在家敲起了代码:
测试的代码是这样的:

一个服务端,一个客户端,tcp建立连接,服务端以每秒30帧,(每个SendFrame操作之间休眠 usleep(100*10000/30)),每帧分成1500 Byte的小帧多次发送(小帧之间的发送间隔时间,不休眠)。服务端记录下发送端每一次发送一帧前的时间点,图中Time_send,客户端记录下每一帧接受完的时间点Time_reciv. 这两个时间差,即一帧数据的传输延迟。(前提是服务端和客户端都有相同的系统时间的情况下,记录的时间才有参考价值,为保证这一点,先在一个系统上测试,这里在虚拟机上 开启两个终端,使用本地回环网络 127.0.0.1 ,一个终端作为server, 另一个终端作为client。 同时为方便比较,记录下时间的同时也把整个发送/接受到的数据一并写入了log文件。)结果如下:

可以看到,竟然达到了975231-736331=238900 微秒,也就是239毫秒。这可是本地回环网络,虽然我的环境是虚拟机ubuntu,这结果,相当不能接受。回头来看,每一次发送一帧,300Kb, 分成了205个小包发送。每一个包调用一次sendto() 发送。如果把上面的rtp分包操作去掉,不进行分包,直接调用一次 sendto()发送300Kb. 测试结果

 

298075-296098=1977微秒,也就是2ms. 这,才是应该有的速度。。。。。。。
如果说硬要强行解释一番的话,只能说,sendto() 系统调用,需要消耗资源,要尽量减少频繁调用,上诉的一帧数据分成 205 次sendto()发送,明显比一次调用sendto() 耗时多得多。 而mtu分包,内核的tcp/ip协议栈会自行处理,如期交给应用层自己分包,多次调用系统调用sendto,还不如一次调用sendto,分包工作就交给 tcp/ip 协议栈自行处理。
至于为什么RTP要在应用层协议自己分包,还不太明白。总之,live555也好,vlc也好,发送rtp都在应用层(rtp层)自行分了包,也就是上面的200多ms延迟的做法。

实际验证:
使用 live555 testOnDemandRTSPServer.cpp 测试h264服务, 同时使用 testRTSPClient.cpp 接受流,开启 testRTSPClient.cpp中的 #define REQUEST_STREAMING_OVER_TCP True, 用rtp-over-tcp, 然后在RTPInterface.cpp 的函数 sendDataOverTCP()的开始出添加打印信息:(也就是系统调用send()函数之前添加)
 printf("send overt tcp :size %d \n",dataSize); //或者用live555里面通用的 env <<  输出。

Boolean RTPInterface::sendDataOverTCP(int socketNum, u_int8_t const* data, unsigned dataSize, Boolean forceSendToSucceed) {
 printf("send overt tcp :size %d \n",dataSize);或者用live555里面通用的 env <<  输出

  int sendResult = send(socketNum, (char const*)data, dataSize, 0/*flags*/);
....
}


以下为实际输出,可以看到server端,每次调用send()发送数据,都不会超过145Byte字节,这个数值对应在 源码MultiFramedRTPSink.cpp  宏定义#define RTP_PAYLOAD_MAX_SIZE 1456 。
不仅如此,每次发送一帧数据多次调用send(),还在每次发送之前单独发送一个 rtp-overt-tcp 需要的额外的 4字节数据。【这个是由于需要同一套上层发送接口,要同时支持rtp-over-tcp 和 rtp-over-udp的原因吧】因为这个机制,在用live555 tcp推流时,wireshark抓的网络包就不便于分析,字节的通道头和数据可能是分别在两个tcp包中的

上述测试,在android真机上测试,晓龙625 cpu。
live555发送一第一帧 40521 byte的h264帧,在本机loop网络端接受,调用了send() 28X2 = 56次, 耗时 833496-781336=52160 微秒
52ms的传输延迟。

测试代码后续github上传。

发布了96 篇原创文章 · 获赞 27 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/u012459903/article/details/103099705
今日推荐