【问题标题】:Sending files via TCP/IP通过 TCP/IP 发送文件
【发布时间】:2016-02-17 15:10:07
【问题描述】:

我正在尝试使用 Windows 上的 C++ 程序通过 TCP/IP 发送文件。发送和接收工作正常。但在收到的文件中,每 40 个字符后出现两个逗号。例如,如果我发送:

123456789
123456789
123456789
123456789
123456789
123456789
23456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789

接收到的文件是:

123456789
123456789
123456789
123456789
123456789
„123456789
123456789
123456789
123456789
123456789
„123456789
123456789
123456789
123456789

这是发送文件的服务器代码:

static int send_client_file(SOCKET sock, char *Sbuffer){

int n = 0;
char* f_name = "send.txt";
//char* f_name = "server.c";

cout << endl << "Waiting for the client message" << endl;
FILE *fp = fopen(f_name, "r");
if (fp == NULL)
{
    cout << "ERROR : File " << f_name << " not found ";
    perror("fopen()");
    exit(errno);
}

//bzero(Sbuffer, 50); // on vide le buffer d'envoie
memset(Sbuffer, 0, 50);
while((n = fread(Sbuffer, sizeof(char), 50, fp)) > 0)
{
    if((n = send(sock, Sbuffer, strlen(Sbuffer), 0)) < 0)
    {
        perror("send()");
        exit(errno);
    }
    memset(Sbuffer, 0, 50);
}

cout << "file sent" << endl;

return n;
}

这是接收它的客户端代码:

int static recv_server_file(SOCKET sock, char *buffer){

int n = 0;
int m = 0;

cout << endl << "Receiving file from the server..." << endl;
char* f_name = "receive.txt";
FILE *fp = fopen(f_name, "a");
if (fp == NULL)
{
    cout << "ERROR : File " << f_name << "not found " << endl;
    perror("fopen()");
    exit(errno);
}

else {

while(n = recv(sock, buffer, Rbuffer_size, 0))
{
    if (n < 0)
    {
        perror("recv()");
        exit(errno);
    }
    m = fwrite(buffer, sizeof(char), n, fp);

    if(m < n)
    {
        cout << "File write failed." << endl;
        break;
    }

    break;
    memset(buffer, '/0', Rbuffer_size);
}
cout << "ok!" << endl;

fclose(fp);
}
cout << "The received data is : " << buffer << endl ;

return m;

}

如您所见,接收文件中出现了“,”。知道如何解决这个问题吗?

【问题讨论】:

  • 您需要发送代码 sn-ps 说明您的操作方式。
  • 在windows下使用fiddler来调查实际发送的内容。
  • 简短的回答是:停止发送它们。 TCP 是一个可靠的、有序的流,所以它是在你的代码中意外地放入逗号的东西。没有代码 sn-p,我们无话可说。
  • @Brian 我添加了代码。
  • @NicolasHolthaus 添加了代码

标签: c++ tcp client-server tcp-ip


【解决方案1】:

从表面上看,您似乎有缓冲区溢出。请注意,不需要的字符出现在 50 个字节之后(不是您在问题中所说的 40 个字节)。您的缓冲区长度为 50 个字符。

您不能在已读入的缓冲区上调用 strlen(),因为 strlen 需要终止空字符才能工作。也就是说,您需要缓冲区为 51 个字符。

这可能不是唯一的问题,但肯定是其中的一部分。

【讨论】:

    【解决方案2】:

    这里有很多问题。

    这是发送文件的服务器代码:

    static int send_client_file(SOCKET sock, char *Sbuffer){
    
    int n = 0;
    char* f_name = "send.txt";
    //char* f_name = "server.c";
    
    cout << endl << "Waiting for the client message" << endl;
    FILE *fp = fopen(f_name, "r");
    if (fp == NULL)
    {
        cout << "ERROR : File " << f_name << " not found ";
        perror("fopen()");
        exit(errno);
    }
    
    //bzero(Sbuffer, 50); // on vide le buffer d'envoie
    memset(Sbuffer, 0, 50);
    

    不必要的。删除。

    while((n = fread(Sbuffer, sizeof(char), 50, fp)) > 0)
    {
        if((n = send(sock, Sbuffer, strlen(Sbuffer), 0)) < 0)
    

    其中的send() 部分应该是send(sock, Sbuffer, n, 0)。这是根本问题。您发送的长度错误。您还假设刚刚读取的数据实际上包含一个空值,对此没有任何保证。 strlen() 调用可能会溢出缓冲区并导致未定义的行为。

        {
            perror("send()");
            exit(errno);
        }
        memset(Sbuffer, 0, 50);
    

    memset() 是不必要的。删除。

    }
    
    cout << "file sent" << endl;
    
    return n;
    }
    

    在这里你返回零。我不明白这一点。

    这是接收它的客户端代码:

    int static recv_server_file(SOCKET sock, char *buffer){
    
    int n = 0;
    int m = 0;
    
    cout << endl << "Receiving file from the server..." << endl;
    char* f_name = "receive.txt";
    FILE *fp = fopen(f_name, "a");
    if (fp == NULL)
    {
        cout << "ERROR : File " << f_name << "not found " << endl;
        perror("fopen()");
        exit(errno);
    }
    
    else {
    
    while(n = recv(sock, buffer, Rbuffer_size, 0))
    {
        if (n < 0)
        {
            perror("recv()");
            exit(errno);
        }
        m = fwrite(buffer, sizeof(char), n, fp);
    
        if(m < n)
        {
            cout << "File write failed." << endl;
            break;
        }
    
        break;
        memset(buffer, '/0', Rbuffer_size);
    

    同样memset() 是不必要的:删除。

    }
    

    【讨论】:

      【解决方案3】:

      在您的客户端代码中,缓冲区实际上从未被 memsetted。这可能是问题所在。

      第一次迭代假定 'buffer' 已经设置为 '\0' 并且此代码是多余的 if (n < 0) { perror("recv()"); exit(errno); } 由于 while(...) 已经检查了这一点,并且在迭代结束时,您在 memset 之前跳出了循环,这样做会使整个循环变得多余。请执行 memset 以排除那些可能的罪魁祸首,您也可以应用这些建议,但这取决于您。

      编辑: 通过使循环冗余,您可能不会收到所有数据。

      编辑#2: 您也忽略了“发送”的返回值。从 msdn 页面:

      如果没有出错,send返回发送的总字节数,可以小于len参数中请求发送的字节数。否则,返回 SOCKET_ERROR 的值,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

      所以数据可能会被丢弃,因为不能保证它会立即发送所有数据。

      编辑 #3 (很抱歉有很多编辑) 此外,您不会在服务器代码中关闭文件句柄

      【讨论】:

      • memset() 调用是多余的。 perror() 不应被删除。您还没有发现实际问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-05
      • 2016-05-12
      • 2016-07-31
      • 2018-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多