天天看點

java-網絡程式設計-大檔案搬運

一切源于:

阿裡搬磚頭比賽說好是Client端線程級的同步阻塞請求,結果一幫人用了協程來完成這件事。其實吧,我想說就算用協程來完成,其實本質也和異步差不多(就網絡通訊層),不過卻激發了我的好奇心,因為比賽的結果是1G極限,隻用了3秒!

3秒…如果我們将題目往對我有利的思考方向改變下,不再是Client端線程級的同步阻塞,隻要求Server端請求應答同步即可。即:Server端在沒收到一個請求之前,不能提前将下一個應答發出!如果我将題目修改為這樣,我也不見得非常有信心能将時間控制在3秒以内!

是以這裡立了個小項目來驗證不同的實作方式下,對網絡傳輸、CPU使用的開銷。項目起名為鐳射,取彙集小請求将能量集中爆發之意。

打算挑戰下極限搬運的。

穿越nat傳輸完整的檔案,而且能自動重傳丢失封包,采用UDP協定,在跨大洲之間進行完整的大檔案(超過2GB)傳輸。

主要解決思路和技術點如下:

對每個封包進行檔案任務标志。可以同時傳輸多個檔案。

發送檔案内容之前,先發送檔案名。然後傳回檔案名收到後的确認,然後再開始傳輸。

對發送封包進行計數,每隔1000個封包(某個時間間隔),接收端發送一個計數封包,報告丢包率。采取降低發送速度等措施。

長期丢包率在99%以上,嘗試提高發送速度一倍。如果丢包率超過10%就降速。

檔案傳輸中斷,有中斷資訊。接收端長期沒有接受到檔案封包,則終止任務。

發送完畢後,接收端發送完畢封包,結束發送。

10000個封包組成一個塊的概念,接收端每收到10000個(某個數字)封包,發送接受塊成功的消息。整個塊不會重複發送。如果塊出現某個封包發送失敗,則重新發送封包。

每個UDP封包,大小是1464位元組,其中64個位元組用來标示任務。

采用java編寫,在web端使用,在tomcat啟動時,也就是servlet的contextlistener啟動的時候,啟動守護程序,監聽udp的80端口。是否與servlet進行協同。為了支援子網,用戶端隻負責發送和上傳資料,不能下載下傳資料。是以計數和控制,可能需要tcp的參與。

首先是封包,為了降低開發工作量。

先使用udp封包的48個位元組。剩下24個還沒想好。

首先将48個位元組分為6個long類型。

第一個long,辨別版本和封包類型。

比如1表示是資料傳輸

2表示是重傳通知等等。

第二個long,是uuid的high位

第三個long,是uuid的low位。

一起辨別一個檔案。

第四個long是包序号。

第五個long是包内封包序号

第六個long是下面的封包長度。

第七個long是在被傳輸檔案裡面的位移量

第八個long是在傳輸檔案裡面的寫入長度

開始為了測試友善,将udp封包的資料長度設為1024,總長度是1024+64=1088

将緩沖視窗設為512KB,即在記憶體開辟一個512KB的緩沖器,當收滿512個UDP封包時,寫記憶體中的資料寫入目标檔案。如果512個封包在機關時間内,沒有收滿,說明有丢包,則選擇丢失的封包重傳。丢包判斷待定。在UDT協定裡面是采用等待4倍的RTT時間判斷的,在4倍的RTT時間後未到達的封包都被判斷為丢失。

chrome的websocket已經實作了udp,估計這個程式的上傳用戶端可以直接拿javascript來寫了。比較理想了。之前的思路有點問題,關于用戶端停止發送這一點,會導緻傳輸效率變低,應該是用戶端繼續發送,直到5個RTT時間後,沒有收到上個window結束信号之後,再停止發送。

UDP之是以比TCP效率高,本質原因是TCP的一個bug,TCP将RTT時間和帶寬聯系在一起,片面認為RTT時間越長,帶寬越低,而真實情況是,RTT和帶寬沒有直接關系。如果跟RTT建立聯系了,我寫UDP傳輸就沒意思了。

//解析中靶情況