I would like to implement a client-server architecture running on Linux using sockets and C/C++ language that is capable of sending and receiving files. Is there any library that makes this task easy? Could anyone please provide an example?
相关问题
- Sorting 3 numbers without branching [closed]
- Multiple sockets for clients to connect to
- How to compile C++ code in GDB?
- Why does const allow implicit conversion of refere
- thread_local variables initialization
This file will serve you as a good
sendfile
example : http://tldp.org/LDP/LGNET/91/misc/tranter/server.c.txtThe 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, andwrite
from that buffer into your socket (you could also usesend
andrecv
, which are socket-specific ways of writing and reading data). The outline would look something like this:Make sure to read the documentation for
read
andwrite
carefully, especially when handling errors. Some of the error codes mean that you should just try again, for instance just looping again with acontinue
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 supportmmap
(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 asendfile
call but no analogousrecvfile
.Beware that
sendfile
is Linux specific; it is not portable to other systems. Other systems frequently have their own version ofsendfile
, but the exact interface may vary (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 implementsendfile
.splice
is a more general purpose API thansendfile
. For a good description ofsplice
andtee
, see the rather good explanation from Linus himself. He points out how usingsplice
is basically just like the loop above, usingread
andwrite
, 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").Do a
man 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.Minimal runnable POSIX
read
+write
exampleUsage:
get two computers on a LAN.
For example, this will work if both computers are connected to your home router in most cases, which is how I tested it.
On the server computer:
Find the server local IP with
ifconfig
, e.g.192.168.0.10
Run:
On the client computer:
Outcome: a file
output.tmp
is created on the sever computer containing'ab\ncd\n'
!server.c
client.c
GitHub upstream.
Further comments
Possible improvements:
Currently
output.tmp
gets overwritten each time a send is done.This begs for the creation of a simple protocol that allows to pass a filename so that multiple files can be uploaded, e.g.: filename up to the first newline character, max filename 256 chars, and the rest until socket closure are the contents. Of course, that would require sanitation to avoid a path transversal vulnerability.
Alternatively, we could make a server that hashes the files to find filenames, and keeps a map from original paths to hashes on disk (on a database).
Only one client can connect at a time.
This is specially harmful if there are slow clients whose connections last for a long time: the slow connection halts everyone down.
One way to work around that is to fork a process / thread for each
accept
, start listening again immediately, and use file lock synchronization on the files.Add timeouts, and close clients if they take too long. Or else it would be easy to do a DoS.
poll
orselect
are some options: How to implement a timeout in read function call?A simple HTTP
wget
implementation is shown at: How to make an HTTP get request in C without libcurl?Tested on Ubuntu 15.10.