2015-06-16 19 views
0

我想实现一个简单的文件传输。下面是我测试的两种方法:发送文件在套接字编程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%,而方法一中为100%。传输文件的最佳方法是什么?

+0

您的网络堆栈希望阻止您一次只通过线路发送5个字节。赞美Nagle! –

+0

我使用了5个字节进行更简单的测试(因为.txt文件尺寸较小,内容可以很容易比较),并知道我的方法是否可行。如果是这样,那么我打算增加它到1024或其他东西。 –

+2

'strcat'可能正在杀死你。你发送的内容不一定是NULL终止的,所以'strcat'不知道在哪里结束。 – user4581301

回答

1

不同意Galik。最好不要使用strcat,strncat或除了预期的输出缓冲区之外的任何东西。

TCP是knda乐趣。你永远不知道你会得到多少数据,但你会得到它或错误。

这将一次读取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; 
} 
+0

我在这一行上得到错误'outfile.write(buffer,size);'当我尝试使用std :: unique_ptr buffer(new char [size]);' –

+0

谢谢。这教给我不要编译。更正的例子,增加了更好的版本。 – user4581301

+0

方法二的问题在于,一旦文件低于最大值,让我尝试添加。 ty –

3

什么是传输文件的最佳方法?

通常我不喜欢回答问题什么是最好的方法。但在这种情况下,它是很明显的:

  1. 您发送的文件大小和网络字节序的校验和,然后开始传送
  2. 发送更多的报头数据(如文件名)任选
  3. 客户端读取文件大小和校验和,并将其解码为主机字节顺序
  4. 您以合理大小的块发送文件数据(5个字节不是合理的大小),块应该匹配tcp/ip帧最大可用有效负载大小
  5. 您在客户端按块接收块,直到先前发送的文件si泽匹配
  6. 您计算在客户端接收数据的校验,并检查它是否匹配接收到一个beforhand

注:你并不需要结合在客户端的所有内存块中,只是将它们附加到存储介质中的文件中。校验和(CRC)通常也可以通过运行数据块来计算。

+0

我所做的是..我首先发送包含文件名和文件大小的标题,然后我计划循环直到满足文件大小。 –

+0

o我也想问,我是否需要在客户端分割文件大小?或者如果我将它们发送到1去就好了? –

+0

我想让我的代码更灵活,我想如果文件大小是'14000000'字节。 –

1

我看到的最初的问题是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; 

} 

除此之外,你应该为错误检查所以插座库可以告诉你,如果出了什么差错与通信。

+0

这个伎俩。谢谢。只有一个问题,这是否会变得灵活?假设病态增加文件大小。 –

+0

@CarloBrew灵活的方式?您显然需要重新编写它,以便您可以处理可变长度的文件。如果是我,我会使用'std :: vector '而不是原始分配的char数组。 – Galik