【问题标题】:Send a file from Client to a Server将文件从客户端发送到服务器
【发布时间】:2015-05-02 16:21:38
【问题描述】:

我正在用 C 语言开发一个客户端/服务器程序。服务器向客户端发送一个 txt 文件,但名称已损坏。内容不错,只是名字不好。

谁能告诉我为什么?谢谢!

这是发送文件的代码:

fd = open(appoggio1, O_RDONLY);
if (fd < 0) {
  fprintf(stderr, "unable to open '%s': %s\n", appoggio1, strerror(errno));
  exit(1);
}
while ((nread = read(fd, buffer2, sizeof(buffer2))) > 0) 
    {
        write(servers_fd, buffer2, nread);
            read(servers_fd,buffer2,sizeof(char));
    }

    printf("Trasmissione completata con successo\n\n");

    write(servers_fd,fine,strlen(fine)); 
    read(servers_fd,fine,strlen(fine));
close(fd);

这是接收文件的代码:

fd = open(nomefile, O_CREAT | O_WRONLY, 0755);

    if (fd < 0) 
    {
        fprintf(stderr, "errore open(): %s\n", strerror(errno));
        exit(errno);
    }
while ((nread = read(conn_fd, buffer, sizeof(buffer))) > 0)
{
    if(!strncmp(buffer,fine,7))
        break;        
    write(fd, buffer, nread);
    write(conn_fd,buffer,sizeof(char));
}
write(conn_fd,fine,strlen(fine));

}

【问题讨论】:

  • 您是否先发送文件名..?什么是nomefile..?
  • 对,就是文件名。
  • 在发送方,发送文件名的代码在哪里..?
  • 你用 valgrind 测试过吗?您是否进行了网络跟踪 (tcpdump) 以查看问题出在哪里,在服务器上还是在客户端上?
  • 您的代码的另一个问题是发送方中的 sizeof(buffer2) 必须等于接收方中的 sizeof(buffer)。否则握手(发回一个字节)将失败。为避免这种情况,最好在文件名之后发送文件大小并且不要握手。在接收方,跟踪到目前为止接收到的字节并将其与预期字节数进行比较。您将知道何时收到所有数据。

标签: c file sockets client server


【解决方案1】:

问题在于您的协议。

您发送文件,然后发送名称。但是客户端无法知道文件何时结束以及名称何时开始。

您可以通过先发送名称的长度然后发送实际名称来修复它:

#include <arpa/inet.h>

// Write the file name with length marker
uint32_t nameLength = htonl(strlen(fine));
write(servers_fd, &nameLength, sizeof nameLength); 
write(servers_fd, fine, strlen(fine)); 

// Write the actual file.

在客户端:

#include <arpa/inet.h>

uint32_t nameLength;
read(conn_fd, &nameLength, sizeof nameLength);
nameLength = ntohl(nameLength);

read(conn_fd, fine, nameLength);
fine[nameLength] = '\0';  // Add nul-terminator to file name.

// Read the rest of the file

htonlntohl 将数字转换为网络字节顺序,即使客户端和服务器使用不同的字节顺序(大/小字节序),您的代码也能正常工作。

注意:除非您对实际文件也使用大小标记,否则客户端将不知道它有多大,并且连接只会对一个文件下载有效。 p>

注意2:我忽略了大小和文件名可能被分成多个网络数据包的可能性。

【讨论】:

  • 我的编译器说“错误:未知类型名称‘uint_32t”。 uint_32t 在什么库中?
  • 对不起,应该是uint32_t
  • 我想我已经非常接近解决方案了!谢谢,我的朋友!我必须发送文件名,我明白了!只有一个问题:“警告:传递 'strlen' 的参数 1 使指针从整数而不进行强制转换 [默认启用] write(servers_fd, fine,strlen(nameLength)); .... 如果我改变 strlen(nameLength )) 使用 strlen(fine) 它可以工作,但文件的名称是“名称”+“文件的所有内容”。问题出在哪里?
  • 发送的文件名不带空终止符。您需要在读取文件名后手动添加字符串终止符。查看更新的答案
  • 我换了面具,效果很好!非常感谢!你救了我!
猜你喜欢
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 2018-06-18
  • 1970-01-01
相关资源
最近更新 更多