繁体   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