使用套接字传输文件

时间:2014-05-01 02:44:12

标签: c sockets file-transfer

我正在尝试使用C中的套接字传输文件(在本例中为.jpg文件)。我有我的客户端和服务器代码,但我不知道为什么传输文件的字节数比原始文件多文件。这是代码:

SERVER

/***************************************************
*
*       Starting to send data file
*
***************************************************/

// Read the size of the file
recv(client.fd_client, &file.size_file, sizeof(int), 0);
recv(client.fd_client, &file.size_string, sizeof(int), 0);
recv(client.fd_client, &file.name_of_file, file.size_string, 0);
printf("Size of the file: %.3f kB\n", file.size_file/1000.);
printf("Receiving the file \"%s\"...\n", file.name_of_file);

if((file.fd_file = creat(file.name_of_file, S_IRWXU)) < 0) {
    error("Can't open the file: ");
}

while(1) {
    bzero(buffer, SIZE_BUF);
    if((numb_bytes = read(client.fd_client, buffer, SIZE_BUF)) < 0) {
        error("Can't read the file.");
    }
    write(file.fd_file, buffer, numb_bytes);
    received += numb_bytes;
    printf("Received: %.3fkB (%.3f/%.3f) kB\n", numb_bytes/1000., recibed/1000., file.size_file/1000.);
    if(numb_bytes == 0)
        break;
}

printf("Recibidos %.3f/%.3f kB\n", recibed/1000., file.size_file/1000.);

客户端

/***************************************************
*
*       Starting to send data file
*
***************************************************/

// Use strncpy!
strcpy(file.name_of_file, argv[3]);
file.fd_file = open(file.name_of_file, 0); 
fstat(file.fd_file, &stat_file);
file.size_file = (unsigned int) stat_file.st_size;
file.size_string = (unsigned int) strlen(file.name_of_file) + 1;
printf("Size of the file: %.3f kB.\n", file.size_file/1000.);
printf("Sending the file \"%s\"...\n", file.name_of_file);

// Send data file
write(conection.sockfd, &file.size_file, sizeof(file.size_file));
write(conection.sockfd, &file.size_string, sizeof(file.size_string));
write(conection.sockfd, &file.name_of_file, sizeof(file.name_of_file));

while(1) {
    sended += sendfile(conection.sockfd, file.fd_file, NULL, SIZE_BUF);
    printf("send: %d\n", sended);
    printf("num_bytes: %d\n", num_bytes);
    if(sended == file.size_file)
        break;
}

printf("Sended %.3f/%.3f kB\n", sended/1000., file.size_file/1000.);

我有几个问题:

  1. 正确传输文件的大小和名称。我不明白为什么当我使用ntohl它给我垃圾。如果我是对的,由于Little和Big Endian,ntohl和ntos都在使用套接字转移号码之前使用。那么为什么会这样呢?
  2. 文件传输也正确,但客户端传输或服务器接收的字节数多于原始文件大小。我尝试传输图像,但无法打开。所以我尝试了客户端的源代码,它很好地到达服务器(具有更多字节,如前所述),但是当我打开它时,顶部有垃圾,然后是源代码。我认为传输很好但是到达的字节比需要的多。任何人都可以告诉我为什么会这样吗?
  3. 我正在以1024kB块传输文件,因为当我尝试通过一次调用发送整个文件时,我永远无法发送它。我在互联网上看到了一些例子,他们修改了某种偏移量,直到它转移并从此开始再次传输。这有必要吗?起初我认为不是,因为我不使用它,文件到达“好”,就像它自动知道从哪里继续读取文件。

1 个答案:

答案 0 :(得分:1)

您正在发送整个名称缓冲区:

write(conection.sockfd, &file.name_of_file, sizeof(file.name_of_file));

但只读取前一个字段发送的长度:

recv(client.fd_client, &file.size_string, sizeof(int), 0);
recv(client.fd_client, &file.name_of_file, file.size_string, 0);

缓冲区大小和字符串长度之间的差异可能是您对附加文件长度的差异。你可以通过改变这个来解决这个问题:

write(conection.sockfd, &file.name_of_file, sizeof(file.name_of_file));

,在您的客户端代码中:

write(conection.sockfd, &file.name_of_file, file.size_string);

我会查看其他子问题,但这是您的文件大小错误的主要原因。我无法对使用htonlntohl的正确性做出明智的决定,因为您没有包含传输这些字段的代码。这可能是一个问题。您可以在所有时间保持结构中的原始大小,并将它们读入临时变量,然后通过在接收方通过ntohl发送所述变量来分配结果,并且只需在发送方发送临时变量(通过htonl收到翻译后)。