jrtplib跨網絡通訊NAT穿透問題解決方法
睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接
前幾篇文章講了使用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,黑客搞遠程控制必備技能啊)。
具體到代碼中的話,如下:
[cpp] view plaincopy
- 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();
這個里面沒做讀寫檢查,不過無所謂了,已經能用了
參考文檔: