fferrin
fferrin

Reputation: 908

Transfer files with sockets

I'm trying to transfer files (in this case, a .jpg file) with sockets in C. I have my client and my server code, but I don't know why the transfer file has more bytes than the original file. Here's the code:

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

CLIENT

/***************************************************
*
*       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.);

And I have a couple of questions:

  1. The transfer of the size and the name of the file happen correctly. What I don't understand is why when I use ntohl it gives me garbage. If I'm right, ntohl and ntos both use before transfer numbers with sockets because of the Little and Big Endian. So why does that happen?
  2. The transfer of the file happens correctly too, but the client transfers or the server receives more bytes than the original file size. I try to transfer an image, but it can't open. So I tried with the source code of the client and it arrives fine to the server (with more bytes, as before), but when I open it has garbage at the top and then the source code. I think that the transfer occurs fine but arrives more bytes than needed. Can anyone give me a clue why this happens?
  3. I'm transferring the file in 1024kB blocks, because when I tried to send the whole file with a single call I never can send it all. I saw examples on the Internet where they fixed some kind of offset until where it transfer and start to transfer again from this point. Is this necessary? At first I think it isn't, because I don't use it and the file arrives "good", like it automatically knows from where to continue the read of the file.

Upvotes: 0

Views: 201

Answers (1)

WhozCraig
WhozCraig

Reputation: 66194

You're sending the entire name buffer:

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

but reading only the length sent from the previous field:

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

The difference between the buffer size and the string length is likely you're differential of additional file length. You can address this by changing this:

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

to this, in your client code:

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

I'll review the additional sub-questions, but this is the primary reason your file size is wrong. I can't really make an educated decision on the correctness of your use of htonl and ntohl because you didn't include the code that transmogs those fields. It could be a problem with that. you may way to keep the sizes native in the structures at all times, and read them into temp vars, assigning the results afterward by sending said-vars through ntohl on the receiving side, and just sending the temp vars (after they receive the translations via htonl) on the sending side.

Upvotes: 1

Related Questions