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

相关文章

SQL server数据库如何下载和安装

《SQLserver数据库如何下载和安装》本文指导如何下载安装SQLServer2022评估版及SSMS工具,涵盖安装配置、连接字符串设置、C#连接数据库方法和安全注意事项,如混合验证、参数化查... 目录第一步:打开官网下载对应文件第二步:程序安装配置第三部:安装工具SQL Server Manageme

C#连接SQL server数据库命令的基本步骤

《C#连接SQLserver数据库命令的基本步骤》文章讲解了连接SQLServer数据库的步骤,包括引入命名空间、构建连接字符串、使用SqlConnection和SqlCommand执行SQL操作,... 目录建议配合使用:如何下载和安装SQL server数据库-CSDN博客1. 引入必要的命名空间2.

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手

SQL Server修改数据库名及物理数据文件名操作步骤

《SQLServer修改数据库名及物理数据文件名操作步骤》在SQLServer中重命名数据库是一个常见的操作,但需要确保用户具有足够的权限来执行此操作,:本文主要介绍SQLServer修改数据... 目录一、背景介绍二、操作步骤2.1 设置为单用户模式(断开连接)2.2 修改数据库名称2.3 查找逻辑文件名

SQL Server数据库死锁处理超详细攻略

《SQLServer数据库死锁处理超详细攻略》SQLServer作为主流数据库管理系统,在高并发场景下可能面临死锁问题,影响系统性能和稳定性,这篇文章主要给大家介绍了关于SQLServer数据库死... 目录一、引言二、查询 Sqlserver 中造成死锁的 SPID三、用内置函数查询执行信息1. sp_w

华为鸿蒙HarmonyOS 5.1官宣7月开启升级! 首批支持名单公布

《华为鸿蒙HarmonyOS5.1官宣7月开启升级!首批支持名单公布》在刚刚结束的华为Pura80系列及全场景新品发布会上,除了众多新品的发布,还有一个消息也点燃了所有鸿蒙用户的期待,那就是Ha... 在今日的华为 Pura 80 系列及全场景新品发布会上,华为宣布鸿蒙 HarmonyOS 5.1 将于 7

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存

Windows Server 2025 搭建NPS-Radius服务器的步骤

《WindowsServer2025搭建NPS-Radius服务器的步骤》本文主要介绍了通过微软的NPS角色实现一个Radius服务器,身份验证和证书使用微软ADCS、ADDS,具有一定的参考价... 目录简介示意图什么是 802.1X?核心作用802.1X的组成角色工作流程简述802.1X常见应用802.

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S