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++?
views:
3603answers:
3Do 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.
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").
This file will serve you as a good sendfile
example : http://tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt