live555推流----局域網延遲的分析

============20191212--追加---------以下主要追究發送比較大的網絡數據時多次調用 系統調用send而產生的耗時問題,不過對於實際上傳輸音視頻實時流的使用場景,往往數據不會這麼大,延遲的性能瓶頸主要不在於此========================

最近在做局域網投屏相關,發現使用vlc做推流和接受,延遲過大(1s以上),改用live555推流和接受,延遲還是過大,局域網中還打不到<200ms的延遲。於是乎研究了好一陣子live555源代碼,也沒有發現其代碼層面故意的休眠的情況出現,苦思冥想數日,不得解,直到這個陽光明媚的週六,突然就想到一個方法,排除live555代碼,有沒有一個方法來直接了當地驗證網絡本來就性能不夠呢,雖然說是局域網,似乎這個懷疑本生就不太然人覺得可靠。 週六就在家敲起了代碼:
測試的代碼是這樣的:

一個服務端,一個客戶端,tcp建立連接,服務端以每秒30幀,(每個SendFrame操作之間休眠 usleep(100*10000/30)),每幀分成1500 Byte的小幀多次發送(小幀之間的發送間隔時間,不休眠)。服務端記錄下發送端每一次發送一幀前的時間點,圖中Time_send,客戶端記錄下每一幀接受完的時間點Time_reciv. 這兩個時間差,即一幀數據的傳輸延遲。(前提是服務端和客戶端都有相同的系統時間的情況下,記錄的時間纔有參考價值,爲保證這一點,先在一個系統上測試,這裏在虛擬機上 開啓兩個終端,使用本地迴環網絡 127.0.0.1 ,一個終端作爲server, 另一個終端作爲client。 同時爲方便比較,記錄下時間的同時也把整個發送/接受到的數據一併寫入了log文件。)結果如下:

可以看到,竟然達到了975231-736331=238900 微秒,也就是239毫秒。這可是本地迴環網絡,雖然我的環境是虛擬機ubuntu,這結果,相當不能接受。回頭來看,每一次發送一幀,300Kb, 分成了205個小包發送。每一個包調用一次sendto() 發送。如果把上面的rtp分包操作去掉,不進行分包,直接調用一次 sendto()發送300Kb. 測試結果

 

298075-296098=1977微秒,也就是2ms. 這,纔是應該有的速度。。。。。。。
如果說硬要強行解釋一番的話,只能說,sendto() 系統調用,需要消耗資源,要儘量減少頻繁調用,上訴的一幀數據分成 205 次sendto()發送,明顯比一次調用sendto() 耗時多得多。 而mtu分包,內核的tcp/ip協議棧會自行處理,如期交給應用層自己分包,多次調用系統調用sendto,還不如一次調用sendto,分包工作就交給 tcp/ip 協議棧自行處理。
至於爲什麼RTP要在應用層協議自己分包,還不太明白。總之,live555也好,vlc也好,發送rtp都在應用層(rtp層)自行分了包,也就是上面的200多ms延遲的做法。

實際驗證:
使用 live555 testOnDemandRTSPServer.cpp 測試h264服務, 同時使用 testRTSPClient.cpp 接受流,開啓 testRTSPClient.cpp中的 #define REQUEST_STREAMING_OVER_TCP True, 用rtp-over-tcp, 然後在RTPInterface.cpp 的函數 sendDataOverTCP()的開始出添加打印信息:(也就是系統調用send()函數之前添加)
 printf("send overt tcp :size %d \n",dataSize); //或者用live555裏面通用的 env <<  輸出。

Boolean RTPInterface::sendDataOverTCP(int socketNum, u_int8_t const* data, unsigned dataSize, Boolean forceSendToSucceed) {
 printf("send overt tcp :size %d \n",dataSize);或者用live555裏面通用的 env <<  輸出

  int sendResult = send(socketNum, (char const*)data, dataSize, 0/*flags*/);
....
}


以下爲實際輸出,可以看到server端,每次調用send()發送數據,都不會超過145Byte字節,這個數值對應在 源碼MultiFramedRTPSink.cpp  宏定義#define RTP_PAYLOAD_MAX_SIZE 1456 。
不僅如此,每次發送一幀數據多次調用send(),還在每次發送之前單獨發送一個 rtp-overt-tcp 需要的額外的 4字節數據。【這個是由於需要同一套上層發送接口,要同時支持rtp-over-tcp 和 rtp-over-udp的原因吧】因爲這個機制,在用live555 tcp推流時,wireshark抓的網絡包就不便於分析,字節的通道頭和數據可能是分別在兩個tcp包中的

上述測試,在android真機上測試,曉龍625 cpu。
live555發送一第一幀 40521 byte的h264幀,在本機loop網絡端接受,調用了send() 28X2 = 56次, 耗時 833496-781336=52160 微秒
52ms的傳輸延遲。

測試代碼後續github上傳。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章