1、ftp
詳細的ftp協議解析,這裡不談(網上多的是),這裡只說重要的地方。
ftp分訊號流和檔案流,訊號流可以根據埠21確定,且21埠的一端為伺服器,找到訊號流。
(1) 如果收到「port」命令,那麼就是主動模式,此時記錄client的ip, port結合serverip和埠20得到傳輸檔案流的tcp流資訊,如果收到「pasv」(或者「epsv」rfc2428, 「lpsv」rfc1639),那麼可以確定為被動模式,那麼server會response 對應的ip,port,結合client的ip,(這裡還拿不到client的檔案流port, 這個port會主動連線server的ip, port)得到傳輸檔案流的tcp流資訊。
(3)傳輸方式,根據命令「type」來判斷。 (我個人的做法是,如果是 「a」, 那麼就是文字的方式寫檔案fopen(filename, 「w」), 如果是其他,那麼就是二進位制的方式寫檔案fopen(filename, 「wb」));
(4) 檔案結束。收到server端傳送的226命令表示檔案結束,或者過程中其他的錯誤碼(寫好日誌)結束寫檔案操作。
那麼根據上面的資訊,找到tcp檔案流,解析出payloadfwrite進檔案就可以了。
這裡要注意,訊號流與檔案流的協同問題,以及檔案流埠復用問題。
2、tftp
tftp非常簡單,就兩種模式rrq,wrq,server使用埠69,傳輸使用udp。
這個過程client 的ip port都不會變,而server發信令的埠使用69,檔案流埠是不一樣的。
(1) rrq
(2) wrq
如上圖,解析命令 opcode = 2表示wrq (寫請求,就是上傳), 得到檔名和傳輸方式,馬上server會發乙個ack過來,此時知道了server段的檔案流port,接下來就是檔案傳輸了,同上面的rrq.
檔案結束標誌:
每個檔案資料報是定長的(
512byte),
如果收到乙個資料報
payload
小於512
,那麼說明檔案結束了
根據上面的描述已經可以得到了檔案流,可以直接建立檔案,寫檔案了。但是如果拿到乙個資料報就寫乙個資料報到檔案中,會有三個問題, 第一:效率較低。因為寫磁碟的速度比較慢,所以會影響整個的效率。第二:產生很多的檔案碎片(因為間隔的寫小檔案塊,會被存到磁碟的各個地方,這個具體的請檢視相應文件)。第三:因為是持續寫,乙個檔案流就要對應乙個檔案控制代碼(如果不對應乙個檔案控制代碼,而且每次都fopen, fclose,那麼效率實在是太低了),在win6 64位電腦上乙個程序能同時開啟的檔案控制代碼數為500個左右(我自己測試的是510個),怎麼處理同時上萬條檔案流的寫問題。
所以,根據上面的問題情況,下面給出非同步寫檔案的解決方案。
定義structdata_block // 檔案內容塊
int npos; // 在buffer內的偏移量
int ndatalen;
file_buffer_into // 檔案快取buffer
char* pbuffer; // buffer 記憶體
int ntotallen; //buffer 總長度
int ncurrentpos; // buffer當前使用位置
map> mapfiletaskdata; // key: 檔案任務控制代碼
structfile_task_info
int ntaskhandle;
string sfilename;
file_mode fm; // 這個是fopen的第二個引數 「w」或者「wb」
定義成員:
listm_listfilewritebuffer; // 用於寫入的buffer
listm_listfilereadbuffer;// 用於讀取buffer資料寫檔案
mapm_mapfiletaskinfo; // 儲存檔案任務
從上面的定義其實可以看出基本思路了, 申請批量(我個人是申請了10個2m大小的buffer)的file_buufer_info用於快取檔案流資料,存入m_listfilewritebuffer中,收到檔案流資料塊的時候,寫入pbuffer中,並且記錄好是哪個檔案的(記錄在mapfiletaskdata中),當第乙個file_buffer_info的buffer塊寫滿了(或定時器到了,見說明
1),那麼就把這個bufferpush到m_listfilereadbuffer中去,同時繼續寫第二個buffer塊,於此同時,讀執行緒會從m_listfilereadbuffer中讀取buffer,將裡面的資料(根據mapfiletaskdata的記錄)讀出來,寫入檔案(見說明
2),讀完了乙個buffer,那麼立刻將此buffer又重新push到m_listfilewritebuffer中使用,就這樣交替非同步的快取機制處理。
這裡有幾點說明:
第一:m_listfilewritebuffer的pop條件。當front的buffer滿了,肯定要彈出,同時如果定時器時間到了,也要彈出。這裡使用定時器的原因是,處理最後資料不能讓buffer滿,而不能讓讀執行緒讀到檔案最後的資料。
第二:寫檔案,這裡我個人也是開闢了乙個寫檔案快取,4k大小,因為讀執行緒是每次會把某個檔案(任務控制代碼)在乙個buffer中的所有資料都出來,所以我把讀到的資料都快取到4k的快取裡面,當滿了,或者結束的時候才呼叫fwrite,這樣效率會更高。
第三:檔案控制代碼,因為整個過程都使用的是任務控制代碼,檔案控制代碼(fopen產生)只有乙個,那就是在讀buffer寫檔案執行緒裡面,一次把buffer裡面的同乙個檔案資料全部讀出來寫入檔案,寫完了,就fclose,再fopen下乙個 (詳 請分析mapfiletaskdatakey為檔案任務控制代碼)。
第四:檔案結束,因為是非同步的,當收到的檔案結束命令的時候,未必它對應的檔案資料塊都寫到了檔案中,如果此時再遍歷所有buffer,把這個檔案資料都寫入檔案,再close,效率太低了。其實很簡單,當檔案結束的時候就不用發什麼停止命令了,直接寫乙個data_block ndatalen = 0就可以了,那麼讀執行緒讀到這個block的時候自然就知道檔案結束了。
下面沒了。
author: min
C 資料流 檔案流 記憶體流 網路流
c 教程全解 c 程式設計中資料流的使用一直不很熟練,沒有乙個系統的認識,但是它的重要性顯然不言而喻。system.io下的stream類是所有資料流的基類,當我們對資料進行逐字節操作時,首先需要將資料轉換為資料流。c 資料流主要分為三類 filestream memorystream networ...
網路協議 TCP互動資料流和資料流成塊
建立在tcp協議上的應用層協議有非常多,如ftp http telnet等,這些協議依據資料傳輸的多少能夠分為兩類 互動資料型別和成塊資料型別。互動資料型別,如 telnet,這類協議一般僅僅做小流量的資料交換。比方每按下乙個鍵,要回顯一些字元。成塊資料型別。如 ftp,這類協議須要傳輸的資料比較多...
資料流建立檔案
以前一直是把檔案轉為資料流存入資料庫儲存,例項多是應用在儲存上。如今需要把excel檔案以二進位製流存入資料庫中,當使用者需要做excel資料分析時,得先把資料流建立為乙個檔案,然後再對這個檔案進行處理。上傳檔案以二進位制儲存資料庫中,insus.net在這裡就不做演示了,因為在insus.net的...