Darwin Streaming Server 支持UDP打洞

2024-04-29 02:08

本文主要是介绍Darwin Streaming Server 支持UDP打洞,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RTSP客户端点播Darwin 视频时,SDP协商后的客户端端口可能是在NAT后面,所以需要Darwin支持NAT打洞的功能,从Darwin的源码看,官方的源码是不支持这个能力的。


通过抓取VLC客户端的包发现,VLC在播放RTSP流时,两次SETUP(音频流和视频分别协商端口)之后,会发送4个UDP打洞的包,但Darwin没有接收这些包,并且根据这些包来源的端口修改远端RTP和RTCP的端口。


文章Darwin Streaming Server 支持UDP穿透中给出了修改方法,尝试之后,发现有两个问题:

1、两次SETUP协商后,Darwin给返回的服务器的RTP和RTCP端口两次都一样

2、客户端发送的打洞的RTP和RTCP打洞的包,并没有接收完全。


针对问题1的修改就是将两次SETUP协商后,Darwin返回的端口不同并且唯一

问题2的修改方法是,在接收到SETUP协商后,开启一个线程接收发送到服务器的RTP和RTCP端口的包,并根据接收到的包的源端口更新远端的RTP和RTCP端口,即使没有收到打洞的包,不做任何处理,还是使用之前协商的端口往外发包。


第一个问题是将RTPStream::Setup方法中的:

fSockets = QTSServerInterface::GetServer()->GetSocketPool()->GetUDPSocketPair(sourceAddr, 0, fRemoteAddr, 
                                                                                        fRemoteRTCPPort);

修改为:

fSockets = QTSServerInterface::GetServer()->GetSocketPool()->CreateUDPSocketPair(sourceAddr, 0);


并将UDPSocketPool::CreateUDPSocketPair方法中两个变量的初值修改为如下:


    UInt16 curPort = kLowestUDPPort + usedNum++;
    UInt16 stopPort = kHighestUDPPort -1; // prevent roll over when iterating over port nums
    UInt16 socketBPort = curPort + 1;



第二个问题修改,头文件增加下面的方法和变量:

        void start_thread_for_nat();void setRemoteRTPPort(int value){fRemoteRTPPort = value; }void setRemoteRTCPPort(int value){fRemoteRTCPPort = value;}UInt16    getRemoteRTPPort(){return  fRemoteRTPPort;}UInt32    getRemoteRTPAddr(){return  fRemoteAddr;}Bool16    getQuitValue(){return  bQuit;}Bool16    getRunningValue(){return  bRunning;}void    setRunningValue(Bool16 value){ bRunning = value;}UInt16    getRemoteRTCPPort(){return  fRemoteRTCPPort;}UDPSocketPair*  getUDPSocketPair(){ return fSockets;}Bool16      bQuit;Bool16      bRunning;


在setup方法最后启动一个监听线程: 

    this->start_thread_for_nat();//errors should only be returned if there is a routing problem, there should be noneAssert(err == QTSS_NoErr);return QTSS_NoErr;
}

实现:

#include <pthread.h>
void* thread_for_nat(void *parms){Bool16      fUpdateRtpPort = false;Bool16      fUpdateRtcpPort = false;SInt64                  currentTime = OS::Milliseconds();RTPStream *pRTPStream = (RTPStream *)parms;if (pRTPStream == NULL){return NULL;}if (pRTPStream->getUDPSocketPair() == NULL){return NULL;}if (pRTPStream->getUDPSocketPair()->GetSocketA() == NULL ||pRTPStream->getUDPSocketPair()->GetSocketB() == NULL){return NULL;}qtss_printf("thread_for_nat enter, pRTPStream:%08x, rtp_port:%d\n", pRTPStream, pRTPStream->getRemoteRTPPort());pRTPStream->setRunningValue(true);while(1){UInt32 iRemoteAddr = 0;UInt16 iRemotePort = 0;char szBuff[64];UInt32 iBufLen = sizeof(szBuff);UInt32 iRecvLen = 0;if (pRTPStream->getQuitValue()){break;}if (!fUpdateRtpPort){OS_Error iRet = pRTPStream->getUDPSocketPair()->GetSocketA()->RecvFrom(&iRemoteAddr, &iRemotePort, szBuff, iBufLen, &iRecvLen);if (OS_NoErr == iRet){if (iRemoteAddr == pRTPStream->getRemoteRTPAddr()&& iRemotePort != pRTPStream->getRemoteRTPPort()&& iRecvLen > 0){qtss_printf("thread_for_nat update GetSocketA iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d, iRemotePort:%d\n", iRet, pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort(), iRemotePort);pRTPStream->setRemoteRTPPort(iRemotePort);fUpdateRtpPort = true;}else{qtss_printf("thread_for_nat update GetSocketA received the same port value, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort());fUpdateRtpPort = true;}}else{//qtss_printf("Setup update GetSocketA iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", iRet, fRemoteRTPPort, fRemoteRTCPPort);}}if (!fUpdateRtcpPort){OS_Error iRet = pRTPStream->getUDPSocketPair()->GetSocketB()->RecvFrom(&iRemoteAddr, &iRemotePort, szBuff, iBufLen, &iRecvLen);if (OS_NoErr == iRet){if (iRemoteAddr == pRTPStream->getRemoteRTPAddr()&& iRemotePort != pRTPStream->getRemoteRTCPPort()&& iRecvLen > 0){qtss_printf("thread_for_nat update GetSocketB iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d, iRemotePort:%d\n", iRet, pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort(), iRemotePort);pRTPStream->setRemoteRTCPPort(iRemotePort);fUpdateRtcpPort = true;} else{qtss_printf("thread_for_nat update GetSocketB received the same port value, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", pRTPStream->getRemoteRTPPort(), pRTPStream->getRemoteRTCPPort());fUpdateRtcpPort = true;}}else{//wait.//qtss_printf("Setup update GetSocketB iRet:%d, fRemoteRTPPort:%d, fRemoteRTCPPort:%d\n", iRet, fRemoteRTPPort, fRemoteRTCPPort);}}if (fUpdateRtcpPort && fUpdateRtpPort){qtss_printf("thread_for_nat exit for update end, break, pRTPStream:%08x, rtp_port:%d\n", pRTPStream, pRTPStream->getRemoteRTPPort());break;}if ( (OS::Milliseconds() - currentTime ) > 2000){qtss_printf("thread_for_nat exaust 2000 ms, break, pRTPStream:%08x, rtp_port:%d\n", pRTPStream, pRTPStream->getRemoteRTPPort());break;}}pRTPStream->setRunningValue(false);gid_thread = -1;return NULL;
}void RTPStream::start_thread_for_nat(){int ret=pthread_create(&gid_thread, NULL, thread_for_nat, (void*)this);if (ret != 0){qtss_printf("err:%d\n", ret);}else{qtss_printf("start_thread_for_nat create OK\n");}
}


这篇关于Darwin Streaming Server 支持UDP打洞的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/944850

相关文章

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

SQL Server清除日志文件ERRORLOG和删除tempdb.mdf

《SQLServer清除日志文件ERRORLOG和删除tempdb.mdf》数据库再使用一段时间后,日志文件会增大,特别是在磁盘容量不足的情况下,更是需要缩减,以下为缩减方法:如果可以停止SQLSe... 目录缩减 ERRORLOG 文件(停止服务后)停止 SQL Server 服务:找到错误日志文件:删除

Windows Server服务器上配置FileZilla后,FTP连接不上?

《WindowsServer服务器上配置FileZilla后,FTP连接不上?》WindowsServer服务器上配置FileZilla后,FTP连接错误和操作超时的问题,应该如何解决?首先,通过... 目录在Windohttp://www.chinasem.cnws防火墙开启的情况下,遇到的错误如下:无法与

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

一文教你解决Python不支持中文路径的问题

《一文教你解决Python不支持中文路径的问题》Python是一种广泛使用的高级编程语言,然而在处理包含中文字符的文件路径时,Python有时会表现出一些不友好的行为,下面小编就来为大家介绍一下具体的... 目录问题背景解决方案1. 设置正确的文件编码2. 使用pathlib模块3. 转换路径为Unicod

JAVA虚拟机中 -D, -X, -XX ,-server参数使用

《JAVA虚拟机中-D,-X,-XX,-server参数使用》本文主要介绍了JAVA虚拟机中-D,-X,-XX,-server参数使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录一、-D参数二、-X参数三、-XX参数总结:在Java开发过程中,对Java虚拟机(JVM)的启动参数进

Windows server服务器使用blat命令行发送邮件

《Windowsserver服务器使用blat命令行发送邮件》在linux平台的命令行下可以使用mail命令来发送邮件,windows平台没有内置的命令,但可以使用开源的blat,其官方主页为ht... 目录下载blatBAT命令行示例备注总结在linux平台的命令行下可以使用mail命令来发送邮件,Win

MySQL 中的服务器配置和状态详解(MySQL Server Configuration and Status)

《MySQL中的服务器配置和状态详解(MySQLServerConfigurationandStatus)》MySQL服务器配置和状态设置包括服务器选项、系统变量和状态变量三个方面,可以通过... 目录mysql 之服务器配置和状态1 MySQL 架构和性能优化1.1 服务器配置和状态1.1.1 服务器选项

定价129元!支持双频 Wi-Fi 5的华为AX1路由器发布

《定价129元!支持双频Wi-Fi5的华为AX1路由器发布》华为上周推出了其最新的入门级Wi-Fi5路由器——华为路由AX1,建议零售价129元,这款路由器配置如何?详细请看下文介... 华为 Wi-Fi 5 路由 AX1 已正式开售,新品支持双频 1200 兆、配有四个千兆网口、提供可视化智能诊断功能,建