簡體   English   中英

在套接字編程TCP中發送文件

[英]Sending files in socket programming tcp

我正在嘗試實現一個簡單的文件傳輸。 下面是我正在測試的兩種方法:

方法一:發送和接收而不拆分文件。 我對文件大小進行了硬編碼,以便於測試。

發件人:

send(sock,buffer,107,NULL); //sends a file with 107 size

接收器:

char * buffer = new char[107];                      
recv(sock_CONNECTION,buffer,107,0);

std::ofstream outfile (collector,std::ofstream::binary);
outfile.write (buffer,107); 

輸出符合預期,該文件未損壞,因為我發送的.txt文件包含與原始內容相同的內容。

方法二:通過在接收方拆分內容進行發送和接收。 每個循環5個字節。

發件人:

send(sock,buffer,107,NULL);   

接收器:

char * buffer = new char[107];                      //total file buffer
char * ptr = new char[5];                           //buffer
int var = 5;                
int sizecpy = size; //orig size

while(size > var ){                                //collect bytes

    recv(sock_CONNECTION,ptr,5,0);

    strcat(buffer,ptr);                     //concatenate
    size= size-var;     //decrease
    std::cout<<"Transferring.."<<std::endl;

    }

    std::cout<<"did it reach here?"<<std::endl;
    char*last = new char[size];

    recv(sock_CONNECTION,last,2,0);    //last two bytes
    strcat(buffer,last);    
    std::ofstream outfile (collector,std::ofstream::binary);
    outfile.write (buffer,107); 

輸出:文本文件包含無效字符,尤其是在開頭和結尾。

問題:如何使方法2起作用? 大小相同,但結果不同。 方法2的原始文件和新文件的相似度約為98〜99%,而方法1的相似度為100%。 傳輸文件的最佳方法是什么?

傳輸文件的最佳方法是什么?

通常,我不會回答“ 什么是最好的方法”之類的問題。 但是在這種情況下,很明顯:

  1. 開始傳輸時,您以網絡字節順序發送了文件大小和校驗和
  2. 可選擇發送更多的標題數據(例如文件名)
  3. 客戶端讀取文件大小和校驗和,並將其解碼為主機字節順序
  4. 您以合理大小的塊(5個字節不是合理的大小)發送了文件數據,這些塊應與tcp / ip幀匹配的最大可用有效負載大小
  5. 您會在客戶端逐塊接收消息,直到匹配先前發送的文件大小為止
  6. 您在客戶端計算接收到的數據的校驗和,並檢查它是否與之前接收到的數據相匹配。

注意:您不需要在客戶端將內存中的所有塊組合在一起,而只需將它們附加到存儲介質上的文件中即可。 通常,校驗和(CRC)通常可以通過遍歷數據塊來計算。

我看到的最初問題是與std :: strcat有關 您不能在未初始化的緩沖區上使用它。 另外,您不復制空終止的c字符串。 您正在復制大小緩沖區。 最好使用std :: strncat來實現:

char * buffer = new char[107];                      //total file buffer
char * ptr = new char[5];                           //buffer
int var = 5;                
int sizecpy = size; //orig size

// initialize buffer
*buffer = '\0'; // add null terminator

while(size > var ){                                //collect bytes

    recv(sock_CONNECTION,ptr,5,0);

    strncat(buffer, ptr, 5); // strncat only 5 chars

    size= size-var;     //decrease
    std::cout<<"Transferring.."<<std::endl;

}

除此之外,您還應該真正進行錯誤檢查,以便套接字庫可以告訴您通信是否出現問題。

與Galik不同意。 最好不要使用strcat,strncat或除預期的輸出緩沖區以外的任何東西。

TCP很有趣。 您永遠不會真正知道將要獲取多少數據,但是您會得到它或出錯。

一次最多讀取MAX個字節。 #define MAX定義為您想要的任何值。

std::unique_ptr<char[]> buffer (new char[size]);
int loc = 0; // where in buffer to write the next batch of data
int bytesread; //how much data was read? recv will return -1 on error                        

while(size > MAX)
{                                //collect bytes
    bytesread = recv(sock_CONNECTION,&buffer[loc],MAX,0);
    if (bytesread < 0)
    {
         //handle error.
    }
    loc += bytesread;
    size= size-bytesread;     //decrease
    std::cout<<"Transferring.."<<std::endl;
}
bytesread = recv(sock_CONNECTION,&buffer[loc],size,0);
if (bytesread < 0)
{
     //handle error
}

std::ofstream outfile (collector,std::ofstream::binary);
outfile.write (buffer.get(),size); 

更加有趣的是,寫入輸出緩沖區,這樣您就不必存儲整個文件。 在這種情況下,MAX應該更大。

std::ofstream outfile (collector,std::ofstream::binary);
char buffer[MAX];
int bytesread; //how much data was read? recv will return -1 on error                        

while(size)
{                                //collect bytes
    bytesread = recv(sock_CONNECTION,buffer,MAX>size?size:MAX,0);
    // MAX>size?size:MAX is like a compact if-else: if (MAX>size){size}else{MAX}
    if (bytesread < 0)
    {
         //handle error.
    }
    outfile.write (buffer,bytesread); 
    size -= bytesread;     //decrease
    std::cout<<"Transferring.."<<std::endl;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM