|
Project Information
Members
Featured
Downloads
Links
|
Aboutsendfile(2) is a system call which provides a "zero-copy" way of copying data from one file descriptor to another (a socket). The phrase "zero-copy" refers to the fact that all of the copying of data between the two descriptors is done entirely by the kernel, with no copying of data into userspace buffers. This is particularly useful when sending a file over a socket (e.g. FTP). The normal way of sending a file over a socket involves reading data from the file into a userspace buffer, then write that buffer to the socket via send() or sendall(): # how a file is tipically sent
import socket
file = open("somefile", "rb")
sock = socket.socket()
sock.connect(("127.0.0.1", 8021))
while True:
chunk = file.read(65536)
if not chunk:
break # done
sock.sendall(chunk)This copying of the data twice (once into the userland buffer, and once out from that userland buffer) imposes some performance and resource penalties. sendfile(2) syscall avoids these penalties by avoiding any use of userland buffers; it also results in a single system call (and thus only one context switch), rather than the series of read(2) / write(2) system calls (each system call requiring a context switch) used internally for the data copying. import socket
from sendfile import sendfile
file = open("somefile", "rb")
sock = socket.socket()
sock.connect(("127.0.0.1", 8021))
offset = 0
while True:
sent = sendfile(sock.fileno(), file.fileno(), offset, 65536)
if sent == 0:
break # done
offset += sentA simple benchmarkThis benckmark script implements the two examples above and compares plain socket.send() and sendfile() performances in terms of CPU time spent and bytes transmitted per second resulting in sendfile() being about 3x faster. send()
sendfile()
When do you want to use it?Basically any application sending files over the network can take advantage of sendfile(2). HTTP and FTP servers are a typical example. proftpd and vsftpd are known to use it, so is pyftpdlib. API documentationsendfile module provides a single function: sendfile(). sendfile.sendfile(out, in, offset, nbytes, header="", trailer="", flags=0) Copy nbytes bytes from file descriptor in (a regular file) to file descriptor out (a socket) starting at offset. sendfile.SF_NODISKIO Parameters for the flags argument, if the implementation supports it. They are available on FreeBSD platforms. See FreeBSD's man sendfile(2). Differences with send()
Supported platformsThis module works with Python versions from 2.5 to 3.3. The supported platforms are:
SupportFeel free to mail me at g.rodola[AT]gmail[DOT]com or post on the the mailing list: http://groups.google.com/group/py-sendfile StatusAs of now the code includes a solid test suite and it should be ready for production use. Recently it's been included in pyftpdlib project; hopefully that's going to tell whether it's actually stable or not. Authorspysendfile was originally written by Ben Woolley including Linux, FreeBSD and DragonFly BSD support.
|