简体   繁体   English

在套接字编程TCP中发送文件

[英]Sending files in socket programming tcp

I am trying to implement a simple file transfer. 我正在尝试实现一个简单的文件传输。 Below here is two methods that i have been testing: 下面是我正在测试的两种方法:

Method one: sending and receiving without splitting the file. 方法一:发送和接收而不拆分文件。 I hard coded the file size for easier testing. 我对文件大小进行了硬编码,以便于测试。

sender: 发件人:

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

receiver: 接收器:

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

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

The output is as expected, the file isn't corrupted because the .txt file that i sent contains the same content as the original. 输出符合预期,该文件未损坏,因为我发送的.txt文件包含与原始内容相同的内容。

Method two: sending and receiving by splitting the contents on receiver's side. 方法二:通过在接收方拆分内容进行发送和接收。 5 bytes each loop. 每个循环5个字节。

sender: 发件人:

send(sock,buffer,107,NULL);   

Receiver: 接收器:

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); 

Output: The text file contains invalid characters especially at the beginning and the end. 输出:文本文件包含无效字符,尤其是在开头和结尾。

Questions: How can i make method 2 work? 问题:如何使方法2起作用? The sizes are the same but they yield different results. 大小相同,但结果不同。 the similarity of the original file and the new file on method 2 is about 98~99% while it's 100% on method one. 方法2的原始文件和新文件的相似度约为98〜99%,而方法1的相似度为100%。 What's the best method for transferring files? 传输文件的最佳方法是什么?

What's the best method for transferring files? 传输文件的最佳方法是什么?

Usually I'm not answering questions like What's the best method . 通常,我不会回答“ 什么是最好的方法”之类的问题。 But in this case it's obvious: 但是在这种情况下,很明显:

  1. You sent the file size and a checksum in network byte order, when starting a transfer 开始传输时,您以网络字节顺序发送了文件大小和校验和
  2. Sent more header data (eg filename) optionally 可选择发送更多的标题数据(例如文件名)
  3. The client reads the file size and the checksum, and decodes it to host byte order 客户端读取文件大小和校验和,并将其解码为主机字节顺序
  4. You sent the file's data in reasonably sized chunks (5 bytes isn't a reasonable size), chunks should match tcp/ip frames maximum available payload size 您以合理大小的块(5个字节不是合理的大小)发送了文件数据,这些块应与tcp / ip帧匹配的最大可用有效负载大小
  5. You receive chunk by chunk at the client side until the previously sent file size is matched 您会在客户端逐块接收消息,直到匹配先前发送的文件大小为止
  6. You calculate the checksum for the received data at the client side, and check if it matches the one that was received beforhand 您在客户端计算接收到的数据的校验和,并检查它是否与之前接收到的数据相匹配。

Note: You don't need to combine all chunks in memory at the client side, but just append them to a file at a storage medium. 注意:您不需要在客户端将内存中的所有块组合在一起,而只需将它们附加到存储介质上的文件中即可。 Also the checksum (CRC) usually can be calculated from running through data chunks. 通常,校验和(CRC)通常可以通过遍历数据块来计算。

The initial problems I see are with std::strcat . 我看到的最初问题是与std :: strcat有关 You can't use it on an uninitialized buffer. 您不能在未初始化的缓冲区上使用它。 Also you are not copying a null terminated c-string. 另外,您不复制空终止的c字符串。 You are copying a sized buffer. 您正在复制大小缓冲区。 Better to use std::strncat for that: 最好使用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;

}

beyond that you should really as error checking so the sockets library can tell you if anything went wrong with the communication. 除此之外,您还应该真正进行错误检查,以便套接字库可以告诉您通信是否出现问题。

Disagree with Galik. 与Galik不同意。 Better not to use strcat, strncat, or anything but the intended output buffer. 最好不要使用strcat,strncat或除预期的输出缓冲区以外的任何东西。

TCP is knda fun. TCP很有趣。 You never really know how much data you are going to get, but you will get it or an error. 您永远不会真正知道将要获取多少数据,但是您会得到它或出错。

This will read up to MAX bytes at a time. 一次最多读取MAX个字节。 #define MAX to whatever you want. #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); 

Even more fun, write into the output buffer so you don't have to store the whole file. 更加有趣的是,写入输出缓冲区,这样您就不必存储整个文件。 In this case MAX should be a bigger number. 在这种情况下,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