前幾篇文章講了使用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();
這個裡面沒做讀寫檢查,不過無所謂了,已經能用了
參考文檔: