天天看點

jrtplib跨網絡通訊NAT穿透問題解決方法

前幾篇文章講了使用jrtplib在Android和pc端進行通訊的方法

在實際項目中,手機端和pc端一般不會在同一個子網内,兩者之間聯絡可能要走路由器之類的NAT(網絡位址轉換 Network Address Translation))裝置

假設服務端IP位址為 112.20.30.40,管理多個攝像頭

服務端建立一個serversocket綁定固定的端口如8000,用來接收用戶端的請求

對于不同的攝像頭分别建立不同的rtpsession,用來發送視訊流到用戶端,比如“camera1”對應的rtp端口為18000

當用戶端請求此攝像頭資料時,便将用戶端的ip和rtp端口加到rtpsession的destination中(觀察者模式),然後發送視訊資料

用戶端(IP假設為192.168.1.100), 建立rtp對象用來接收服務端發送的視訊流,端口設定為9000,

用戶端連接配接到的路由器IP位址為192.168.1.1,對應的外網位址為172.20.30.200,

但NAT的行為模式是,隻能從内部開門,也就是說,服務端如果想通過18000端口往用戶端的9000端口發資料的話

這個資料在路由器上就直接被抛棄掉了,不會轉發到用戶端,解決方法很簡單,用戶端在接收資料之前先往服務端的18000端口随便發個資料,

這樣門就打開了,服務端的資料就可以進來了(專業一點的術語叫UDP hole punching,黑客搞遠端控制必備技能啊)。

具體到代碼中的話,如下:

int rtpsock = ((RTPUDPv4TransmissionInfo *)m_pRTPSessionVideo->GetTransmissionInfo())->GetRTPSocket();  

        if (rtpsock != -1) {  

            sockaddr_in skAddr;  

            unsigned long destAddr = inet_addr("112.20.30.40");  

            memcpy(&skAddr.sin_addr, &destAddr, sizeof(destAddr));  

            skAddr.sin_port = htons(18000);  

            skAddr.sin_family = AF_INET;  

            status = connect(rtpsock, (sockaddr *)&skAddr, sizeof(skAddr));  

            LOGI("status is %d", status);  

            int sendcount = send(rtpsock, (void *)"test", sizeof("test"), 0);  

            LOGI("rtpsock is %d, send data %d", rtpsock,sendcount);  

        }  

        m_pRTPSessionVideo->BeginDataAccess();  

這個裡面沒做讀寫檢查,不過無所謂了,已經能用了

參考文檔: 

繼續閱讀