sendfile Zero-Copy: Which Data Copies Are Eliminated?

This article compares traditional file-to-network data transfer (4 copies, 2 CPU copies) with Linux sendfile zero-copy (2 DMA copies, 0 CPU copies), explaining how sendfile eliminates two CPU-mediated copies by moving data directly from kernel page cache to socket buffer, while noting limitations like file-to-socket only, no compression, and UDP incompatibility.

Deepin Linux
Deepin Linux
Deepin Linux
sendfile Zero-Copy: Which Data Copies Are Eliminated?

The article opens with a package-delivery analogy: traditional data transfer from disk to network involves multiple hand-offs, just as a parcel passes through several depots. In conventional I/O, reading a file and sending it over the network requires four data copies — two performed by DMA (disk to kernel buffer, socket buffer to NIC) and two by the CPU (kernel buffer to user buffer, user buffer to socket buffer). This CPU involvement consumes cycles and memory bandwidth, hurting performance under high concurrency.

Traditional Data Transfer Copy Process

The author breaks down the four copies:

Disk to kernel buffer (DMA) — Hardware moves data without CPU intervention. Example: reading a video file, the disk controller DMA-transfers data to the kernel's page cache while the CPU handles other tasks.

Kernel buffer to user buffer (CPU copy via read ) — Because user-space applications cannot directly access kernel memory, a read system call triggers a CPU copy into the application's buffer. Example: a video player copies data from kernel cache to its user-space buffer for decoding.

User buffer to socket buffer (CPU copy via write ) — After any user-space processing, a write system call copies data from the user buffer into the kernel's socket buffer for network transmission. Example: the video player copies processed frames to the socket buffer for live streaming.

Socket buffer to NIC (DMA) — The kernel uses DMA to move data from the socket buffer to the network card for wire transmission.

A complete C example demonstrates the traditional loop:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BUF_SIZE 4096

int main() {
    int fd_file = open("video.mp4", O_RDONLY);
    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    char user_buf[BUF_SIZE];
    ssize_t n;
    while ((n = read(fd_file, user_buf, BUF_SIZE)) > 0) {
        /* read triggers:
         * 1. Disk DMA to kernel file buffer (no CPU copy)
         * 2. CPU copies kernel buffer to user_buf (first CPU copy)
         */
        ssize_t send_len = write(sock_fd, user_buf, n);
        /* write triggers:
         * 1. CPU copies user_buf to socket kernel buffer (second CPU copy)
         * 2. Kernel DMA from socket buffer to NIC (no CPU copy)
         */
    }
    close(fd_file);
    close(sock_fd);
    return 0;
}

sendfile Zero-Copy Technology

sendfile

is a Linux system call that transfers file data directly from the kernel's page cache to a socket buffer, bypassing user space entirely. Its workflow:

User process calls sendfile — context switch to kernel mode (first switch).

Kernel uses DMA to copy disk data into kernel page cache.

Kernel copies data from page cache directly to socket buffer (no user buffer involved).

Kernel uses DMA to move socket buffer data to NIC. sendfile returns — context switch back to user mode (second switch).

A sendfile server example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/sendfile.h>
#include <fcntl.h>
#include <errno.h>

#define PORT 8080
#define FILE_NAME "test.txt"
#define LISTEN_BACKLOG 5

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr;
    int file_fd = open(FILE_NAME, O_RDONLY);
    off_t file_size = lseek(file_fd, 0, SEEK_END);
    lseek(file_fd, 0, SEEK_SET);
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    listen(server_fd, LISTEN_BACKLOG);
    client_fd = accept(server_fd, NULL, NULL);
    ssize_t send_len = sendfile(client_fd, file_fd, NULL, file_size);
    close(client_fd);
    close(server_fd);
    close(file_fd);
    return 0;
}

Copies Eliminated by sendfile

Traditional: 4 copies (2 CPU, 2 DMA). sendfile: 2 copies (both DMA). The two CPU copies are removed:

Avoid kernel-to-user copy — Data stays in kernel page cache; no read into user buffer. Example: a file download server sends data straight from page cache to network without an intermediate application buffer.

Avoid user-to-socket copy — Since data never enters user space, the write copy is unnecessary. Example: a video streaming server pushes frames from page cache directly to the socket buffer, cutting one copy and reducing latency.

Limitations of sendfile

Transfer form restriction — Designed only for file-to-socket transfers. Cannot move data between memory buffers (e.g., in-memory buffer to network).

File processing restriction — No built-in compression, encryption, or modification. If a file must be compressed before sending, the application must process it first (requiring user-space copies), then use another transfer method.

Network protocol restriction — Works with TCP but not UDP. Real-time applications like video conferencing or online games that rely on UDP cannot benefit from sendfile.

In summary, sendfile zero-copy dramatically reduces CPU overhead and memory bandwidth usage for static file serving by eliminating two CPU-mediated copies. However, its applicability is limited to file-to-socket TCP scenarios where no intermediate data transformation is required.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

kernelLinuxDMAsendfilezero-copysystem-callnetwork-programminguser-space
Deepin Linux
Written by

Deepin Linux

Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.