2015年8月1日 星期六

可正確續傳的4G大檔案-client/server

整理一下上學期網路程式設計的作業報告,老師那時候講了一些在接收端(client)和發送端(server)上要注意研究的問題:
---------------------------------------------------------------------------------------------------------------------
狀況一: 單個client完整傳完
狀況二: client斷或server斷後續傳
狀況三: 多個client同ip同時傳,而某個client斷續傳
狀況四: 檔案已存在
狀況五: client網路斷掉timeout後離開再連Server續傳
狀況六: client網路斷掉後timeout之前連回去可續傳

---------------------------------------------------------------------------------------------------------------------

續傳程式大致上就幾個重點:

第一點是fseek的使用( http://linux.die.net/man/3/fseek )
fseek內的第一個參數fp2是檔案指標,第二個參數0代表指標要移動的offset值,第三個參數SEEK_END代表一種Action將指標移至最尾端。

check=fseek( fp2, 0, SEEK_END); //將檔案指標指到檔案最後.offset=0
total= ftell(fp2);                //回傳指標所移動的值,代表從檔案指標從開始到目前位置共多長

通常fseek會搭配ftell來得到檔案指標的位置,fseek回傳值check等於0代表成功執行,-1代表有錯誤。而作業要用到fseek的部分來做移動續傳檔案的檔案指標,再接著現有的部分傳完剩下的內容。


第二點fseek前的檔案指標開啟:
我這裡先使用找檔案的指令放在程式碼裡面,讓接收端掃描要求的檔案如果存在就把檔案大小當offset傳給server告訴他client已有完整檔案而server退出process,client也會離開執行,否則就當作offset傳。

如果續傳的情況下,打開檔案指標沒有用 ” a+”反而直接以fseek移動檔案指標來寫檔案會出錯,因為原本fopen打開的型態是以可讀寫方式從頭開始,因此要改成從檔案尾開始讀取寫入,資料才不會亂碼。

 if ( (fp = fopen(Filename, "a+")) == NULL){
                perror_check("fopen continue  error!");
         }


第三點是signal的處理:
用來判斷fork後的child process是否還存在(判斷是否僵屍process),如果完整的結束並且離開會child process會發signal給系統,就會到signal handle function裡做處理,waitpid裡的 ”-1”代表等待所有產生的child process結束,” WNOHANG” 代表沒有child process存在時立即回到這行。

static void handle(int signum){
                printf("clear! memory\n");
                waitpid(-1,NULL,WNOHANG);
}

int main(int argc,char* arv[]){
     signal(SIGCHLD,handle);  //當fork後的child process完成後發出signal並前往handle處理
......}


最後要記得檔案內產生的副函式要加static防止其他檔案用到這個程式產生的副函式而產生錯誤,以及任何socket連線之後結束程式要close 


=======================================================================

狀況一: 單個client完整傳完
左邊terminal是client端,右邊terminal是server端
client端連上server後,收到server端傳過來的檔名和大小,而client端先找自己有沒有該檔案
狀況一是client端沒有該檔案,因此回傳offset=0給server端,讓server從頭開始傳檔案。


完整正確傳完之後,server端要確定以fork出來在用傳送檔案的child process有沒有正確結束,不然會一直佔著記憶體空間。

驗證正確傳完的檔案有無損壞,解壓縮完就知道正確性。

========================================================================



狀況二: client斷或server斷後續傳
狀況二是client端與server端傳送中斷,由於傳送中斷,client端就直接跳回未連線狀態的時候,圖中間也看到檔案傳輸被斷在1.5G左右,而server端只是因為fork出來傳送檔案的child process被中斷,但仍然保持可以讓其他client端進來連線的狀態。


這是client端連回server端的開始畫面(在select timeout之後的重連),client端會先檢查本地有沒有該檔案,再來讀取檔案大小(offset)傳給server端並移動server端檔案指標到該offset的位置進行續傳。


從圖可以看到檔案續傳成功。

=======================================================================

狀況三: 多個client同ip同時傳,而某個client斷續傳
此圖左邊terminal為server端,右邊2個terminal位於同主機內不同資料夾下的client檔對server端進行連線,2個client端都沒有該檔案的情況下進行傳送檔案。


此圖顯示右邊client端連線中斷,但中間client端仍可以保持與server端的檔案傳送。


右邊client端連回server端的畫面(在select timeout之後的重連)即將從1.2G處開始續傳檔案,中間client不受右邊client端重連的影響,持續在傳送檔案。

顯示兩個client端的檔案都接收成功。

=======================================================================

狀況四: 檔案已存在
特別做這個狀況的探討是因為檔案就算存在,也要確確實實檢查client端的檔案是否完整,檔案過大或少都代表與server端的檔案內容不符,因此即便傳完也得試著檢查檔案。

=======================================================================

狀況五: client網路斷掉timeout後離開再連Server續傳

這個狀況五跟狀況二的續傳不太一樣,狀況二是基於傳送失敗而重連續傳,但狀況五的情形是網路斷掉(上圖以兩台VM不同ip下做測試),server端會根據自己程式碼的寫法(select設定timeout 30秒)來判斷client端有無重連(依據server端會發送帶有RST的封包給client接收),若30秒內client沒再次連上網的話,server端會直接關閉client端的socket,代表下次該client的連線屬於重新連線(新的一次三向交握)的續傳。

=======================================================================

狀況六: client網路斷掉timeout後之前連回網路可續傳

如最後所示,連回去後的續傳檔案正確接收


========================================================================
最後,可能會對圖片內傳送檔案的數值有個疑問
" 明明buffer size設整數為什麼傳送或接收端的值不符合size大小值? "

那是因為傳送檔案的時候,不管有沒有跨網段,封包在傳送時不太可能會實際按照你設定的buffer size來做傳輸,反倒是依據網路情況來做分割封包或調整size大小值,因此值就有時大有時小,反之傳送程式buffer size設得太小的話,大概不會被改size值但電腦會對這個傳送程式的process吃非常大的CPU,所以設定size的大小要看當時的檔案來做選擇,這邊我是設50K來做測試。








沒有留言:

張貼留言