1. 程式人生 > >socket傳送二進位制流的一些總結

socket傳送二進位制流的一些總結

第一次實質性的接觸socket通訊方面的工作,所以遇到的問題還真不少,寫篇部落格記錄一下,提升下記憶。

需求是通過私有協議進行二進位制資料的傳輸,必須保證資料包不能被丟失,所以選擇tcp的socket進行通訊。

1. 遇到的第一個問題是客戶端與服務端的socket通訊沒有保持持續的連線狀態

   這個是一個想當然的錯誤。想當然的以為TCP是有連線的通訊,但是你如果長時間不通訊,服務端一直保持著通訊,這對伺服器資源是一種極大的浪費。客戶端與服務端的連線是需要佔用一定資源的,而服務端的資源是有限的。如果一直保持連線狀態,那麼你的伺服器的效能肯定是有問題的。

   解決這個問題的辦法是保活。服務端傳送心跳包,客戶端接受到之後進行迴應。客戶端告訴伺服器,還線上,不要斷開連線。如果客戶端長時間沒有迴應,伺服器斷開與此客戶端的連線,減少資源佔用。

2. 二進位制檔案的讀寫問題

    第一次嘗試讀取二進位制檔案採取了分段讀取的方式。測試過程中發現一個很大的問題:檔案讀取到部分就會中斷讀取。debug下,得出是讀取到了空字元('\0')。這個直接導致一次讀取到內容在傳送前丟失,甚至有些情況下會有空字元,客戶端接受時會產生崩潰現象。

   既然分段不行,就乾脆全部讀取,然後在分段傳送。boost.asio庫支援對vector包裝傳送,分段傳送時,把一塊二進位制流拷貝到vector中,然後整體傳送。

3. 提高二進位制流的傳輸效率

   直接傳輸二進位制流不是一個高效的行為,也不是一個安全的行為。直接傳送一個二進位制流很容易被截獲,從而導致資訊洩露。

   提高二進位制流傳輸效率的辦法就是加密壓縮再發送。伺服器加密壓縮,客戶端解密解壓縮。可採取兩種方式:

   1)整體壓縮,分段傳送

   2)分段壓縮,分段傳送

   要求不是很高的話,採取方式一比較好。簡單粗暴。。

貼一些程式碼,整體讀取二進位制檔案的:

先是C++的:

 1     string fileName = "D:/XtAmpClient/XtAmpTradeClient_x64_3.0.1.14473.exe";
 2     ifstream ifs(fileName, ios_base::binary);
 3 
 4     filebuf* pbuf = ifs.rdbuf();
5 int size = pbuf->pubseekoff(0, ios_base::end, ios_base::in); 6 pbuf->pubseekpos(0, ios_base::in); 7 8 char* buf = new char[size]; 9 pbuf->sgetn(buf, size); 10 ifs.close(); 11 delete []buf;

最後是C的:

 1     const char* fileName = "D:/XtAmpClient/XtAmpTradeClient_x64_3.0.1.14473.exe";
 2     FILE* fp = fopen(fileName, "rb");
 3     if (NULL == fp)
 4     {
 5         cout << "open file failed" << endl;
 6         return ;
 7     }
 8 
 9     fseek(fp, 0, SEEK_END);
10     long size = ftell(fp);
11     rewind(fp);
12 
13     char* buffer = (char*)malloc(sizeof(char) * size);
14     if (NULL == buffer)
15     {
16         cout << "malloc failed" << endl;
17         return ;
18     }
19 
20     int ret = fread(buffer, 1, size, fp);
21     if (ret != size)
22     {
23         cout << "reading failed" << endl;
24         return ;
25     }
26 
27     fclose(fp);
28     free(buffer);

效能上C比C++好一點點,但是C++的程式碼明顯更簡潔。