views:

3603

answers:

3

I have a Server Client structure , both server and client can send and receive file. how to send and receive file in socket programming.
one solution that I think is partition the file and send one by one segment, is there any library for file send and receive in Linux and C/C++?

+7  A: 

Do aman 2 sendfile. You only need to open the source file on the client and destination file on the server, then call sendfile and the kernel will chop and move the data.

florin
+15  A: 

The most portable solution is just to read the file in chunks, and then write the data out to the socket, in a loop (and likewise, the other way around when receiving the file). You allocate a buffer, read into that buffer, and write from that buffer into your socket (you could also use send and recv, which are socket-specific ways of writing and reading data). The outline would look something like this:

while (1) {
    // Read data into buffer.  We may not have enough to fill up buffer, so we
    // store how many bytes were actually read in bytes_read.
    int bytes_read = read(input_file, buffer, sizeof(buffer));
    if (bytes_read == 0) // We're done reading from the file
        break;

    if (bytes_read < 0) {
        // handle errors
    }

    // You need a loop for the write, because not all of the data may be written
    // in one call; write will return how many bytes were written. p keeps
    // track of where in the buffer we are, while we decrement bytes_read
    // to keep track of how many bytes are left to write.
    void *p = buffer;
    while (bytes_read > 0) {
        int bytes_written = write(output_socket, buffer, bytes_read);
        if (bytes_written <= 0) {
            // handle errors
        }
        bytes_read -= bytes_written;
        p += bytes_written;
    }
}

Make sure to read the documentation for read and write carefully, especially when handling errors. Some of the error codes mean that you should just try again, for instance just looping again with a continue statement, while others mean something is broken and you need to stop.

For sending the file to a socket, there is a system call, sendfile that does just what you want. It tells the kernel to send a file from one file descriptor to another, and then the kernel can take care of the rest. There is a caveat that the source file descriptor must support mmap (as in, be an actual file, not a socket), and the destination must be a socket (so you can't use it to copy files, or send data directly from one socket to another); it is designed to support the usage you describe, of sending a file to a socket. It doesn't help with receiving the file, however; you would need to do the loop yourself for that. I cannot tell you why there is a sendfile call but no analogous recvfile.

Beware that sendfile is not portable to other systems, though other systems frequently do have their own version of sendfile, though the interface varies a bit (FreeBSD, Mac OS X, Solaris).

In Linux 2.6.17, the splice system call was introduced, and as of 2.6.23 is used internally to implement sendfile. splice is a more general purpose API than sendfile. For a good description of splice and tee, see the rather good explanation from Linus himself. He points out how using splice is basically just like the loop above, using read and write, except that the buffer is in the kernel, so the data doesn't have to transferred between the kernel and user space, or may not even ever pass through the CPU (known as "zero-copy I/O").

Brian Campbell
Brian, I'm guessing you and florin will not get the check mark as this is almost certainly homework :(
KevinDTimm
What happened to your original answer? You first suggested the 'sendfile' command on the *nix box, now you've given a programmatic solution whilst removing all vestiges of your original answer.
KevinDTimm
I didn't remove all vestiges of it. I just added the skeleton of a standard, `read`/`write` loop above it. I figured that I should explain that first, because even using `sendfile`, you will need to use such a loop to receive the file, and since I'd mentioned `splice` later on, which uses the same pattern.
Brian Campbell
Ah, somehow missed the retention of 'sendfile'. Sorry.
KevinDTimm
+3  A: 

This file will serve you as a good sendfile example : http://tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt

Kornel Kisielewicz