最近碰到一个非常棘手的问题,NVR通过ONVIF协议接入IPC进行录像,在录像时,会发现其中有个别IPC会出现录像断断续续的情况。这种情况很难复现,但是这种情况一旦出现,整个过程会一直持续很长时间,一般是直到重启RTSP Server。

通过苦逼型的大规模测试发现: 
1、IPC与NVR之间是通过RTP over TCP的方式传输数据(这个测试结果很简单就可以知道); 
2、开启1个客户端(通过RTP over TCP传输数据),打开rtsp流后,使用任务管理器强制结束。紧接着马上再开1个客户端,打开rtsp流,稍等一会儿(1分钟左右),后面开启的这个流居然自动断开了。这是一个必现的bug。(这里测试时,客户端可使用VLC,不过VLC默认情况下是使用RTP over UDP的方式传输数据。要使用 over TCP方式接收数据,需要通过以下设置: “工具”->“首选项”,打开首选项对话框后,“显示设置”处点击“全部”单选按钮,在左侧树形菜单依次展开:“输入/编解码器”->“去复用器”->“RTP/RTSP”,选中“使用RTP over RTSP(TCP)”);

通过调试发现: 
1、RTSPServer::createNew()的参数里面有个reclamationTestSeconds参数,该参数默认值为65; 
2、RTSPServer::createNewClientSession创建一个RTSPClientSession实例时,RTSPClientSession构造函数会调用noteLiveness,noteLiveness会设置一个延时任务,该任务的延时时间即为1中的reclamationTestSeconds(其值为秒,需要转换为微秒,回调为livenessTimeoutTask)。noteLiveness除了在构造的时候调用,在RTSP SERVER接收到一个RR数据包后,也会调用(RR其实也用作了一种心跳包了);
3、RTSPServer::incomingConnectionHandler()函数在异常结束上一个客户端后,再打开一个客户端打开rtsp流时,函数中accept返回的socket的值和上一个客户端的socket句柄值是相同的(概率在50%以上,如果这里返回的socket句柄不同,这个bug就不会复现了);

通过以上3条,如果你读过live555的代码,应该知道是怎么回事了。上面2中设置的延时任务的回调函数livenessTimeoutTask,只干了一件事件,就是delete掉RTSPServer::createNewClientSession创建的实例。查看RTSPClientSession的析构函数,发现其居然把RTPInterface::fTCPStreams链表中对应的节点给删掉了。而RTP和RTCP包是通过RTSPServer::sendPacket发送到各个客户端的,在发送的时候,就是直接对RTPInterface::fTCPStreams保存的地址(即socket句柄)进行发送。如果RTPInterface::fTCPStreams中的socket清除了,客户端自然不会再接收到数据,出现断线已经是必然了。至此,断线的原因终于明了:即异常结束掉一个客户端,在65秒内(默认值为65),再开启一个客户端打开流,第二次打开的这条流会在65秒内必然断开,如果客户端有断线自动重连的功能,那么,断断续续的情况就出现了。

通过测试还发现,通过RTP over UDP的方式接收数据时,异常结束客户端,RTSP Server居然会接收到一条TEARDOWN消息,而在TEARDOWN消息的处理过程中,会清理掉client session和RTSP链接,即使用RTP OVER UDP的方式传输数据时,异常结束客户端,并不会出现上述bug,这个让我困惑不少,如果哪位知道,请告诉我原因。

其实解决这个问题,只需要注释掉livenessTimeoutTask中的delete语句就行了,不过这不是最终解决方案,因为会造成内存泄漏,最好的方式是使用SESSION ID和目标地址进行关联,在调用StreamState::endPlaying删除目的地址时,如果SESSION ID不对应,不从链表中清除掉对应的节点就行了。

转自:http://m.blog.csdn.net/blog/zxwangyun/40541023

最新文章

  1. 解读ASP.NET 5 & MVC6系列(14):View Component
  2. Linux命令小结:crontab/netstat/iostat/sar
  3. Swift实现截屏并保存相册
  4. App主界面Tab实现方法
  5. .net发邮件【转】
  6. java对象与json对象间的相互转换
  7. Oracle错误代码大全
  8. jdk+jira配置
  9. codeforces868D Huge Strings
  10. 【Redis篇】Redis集群安装与初始
  11. java设计模式——适配器模式 Java源代码
  12. BootStrap顺序验证和指定字符个数发送请求
  13. springboot 格式化返回日期
  14. [20180823]IMU与db link.txt
  15. 一脸懵逼学习KafKa集群的安装搭建--(一种高吞吐量的分布式发布订阅消息系统)
  16. mount: mounting proc on /proc failed: Device or resource busy
  17. py-day3-3 python 函数的作用域
  18. (转)cenntos 安装mongodb
  19. JS调试技巧
  20. Angular2入门:TypeScript的函数 - 函数定义、可选参数、默认参数和函数重载

热门文章

  1. [Windows Azure] How to Deploy a Database to Windows Azure
  2. Vue.js使用-组件(上篇)
  3. 对JSON格式的城市按照拼音首字母排序
  4. jdango 部署之nginx+uwsgi
  5. 3. DNN神经网络的正则化
  6. 基于jq流畅度非常好的图片左右切换焦点图
  7. TaskWarrior windows版制作
  8. [转]看懂Oracle执行计划
  9. 电子印章在Odoo的实现步骤
  10. mongoDB之监控工具mongostat