Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C, sendfile() and send() difference?

sendfile() copies data between two file descripters within kernel space. Somewhere I saw if you are writing a web server in C in linux you should use send() and recv() instead of using write() and read(). So is the send() use the kernel space as well?

Whatever I use for sending - sendfile() or send() - on the client side I'll be using recv() right?

On the flip side, man page says: "The only difference between send() and write(2) is the presence of flags. With a zero flags argument, send() is equivalent to write(2)."

like image 735
samsamara Avatar asked Nov 04 '12 02:11

samsamara


People also ask

What is the difference between sendfile() and send()?

C, sendfile () and send () difference? sendfile () copies data between two file descripters within kernel space. Somewhere I saw if you are writing a web server in C in linux you should use send () and recv () instead of using write () and read (). So is the send () use the kernel space as well?

Why does sendfile take so long to complete?

To increase network efficiency, the underlying system may delay transmission until a significant amount of outgoing data is collected. A successful completion of the SendFile method means that the underlying system has had room to buffer your data for a network send.

What is the offset of sendfile ()?

If offset is not NULL, then it points to a variable holding the file offset from which sendfile () will start reading data from in_fd. When sendfile () returns, this variable will be set to the offset of the byte following the last byte that was read.

What file type does sendfile () transfer to out_FD?

Since Linux 2.6.33 it can be any file. If it is a regular file, then sendfile () changes the file offset appropriately. If the transfer was successful, the number of bytes written to out_fd is returned.


2 Answers

If fd is a socket file descriptor, then these system calls are identical:

  • send(fd, data, length, 0) is the same as write(fd, data, length)
  • recv(fd, data, length, 0) is the same as read(fd, data, length)

So, unless you need to set a non-zero flags parameter, it makes no difference whether you use send/recv or write/read.

The sendfile system call is an optimization. If you have a socket sockfd and a regular file filefd and you want to copy some file data to the socket (e.g. if you're a web server serving up a file), then you might write it like this:

// Error checking omitted for expository purposes
while(not done)
{
    char buffer[BUFSIZE];
    int n = read(filefd, buffer, BUFSIZE);
    send(sockfd, buffer, n, 0);
}

However, this is inefficient: this involves the kernel copying the file data into userspace (in the read call) and then copying the same data back into kernel space (in the send call).

The sendfile system call lets us skip all of that copying and have the kernel directly read the file data and send it on the socket in one fell swoop:

sendfile(sockfd, filefd, NULL, BUFSIZE);
like image 78
Adam Rosenfield Avatar answered Oct 07 '22 09:10

Adam Rosenfield


As you have pointed out, the only difference is the flags. send/recv are for networking, whereas read/write are general I/O functions for any file descriptor. send is only useful vs write when you want to use a flag, since the flags are all network related, it doesn't make sense to call send on a non-network file descriptor (nor am I sure whether it's even valid).

Also you should note:

The in_fd argument must correspond to a file which supports mmap(2)-like operations (i.e., it cannot be a socket).

Which means you can't copy from a socket (you can copy to a socket and prior to 2.6.33 you must copy to a socket).

like image 29
CrazyCasta Avatar answered Oct 07 '22 09:10

CrazyCasta