SENDFILE(2)

ИМЯ
sendfile - производит обмен данными между дескрипторами файлов

ОБЗОР
#include <sys/sendfile.h>

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

ОПИСАНИЕ
Вызов sendfile() копирует данные из одного файлового дескриптора в другой. Так как копирование производится в ядре, использование sendfile() более эффективно чем комбинация read(2) и write(2), в которой требуется скопировать данные в и из пользовательского пространства. В in_fd должен указываться файловый дескриптор, открытый для чтения, а в out_fd должен указываться файловый дескриптор, открытый для записи. Если значение offset не равно NULL, то оно указывает на переменную, содержащую файловое смещение с которого sendfile() начнёт чтение данных из in_fd. При завершении sendfile() значение этой переменной будет содержать указатель на следующий байт после последнего прочитанного. Если значение offset не равно NULL, то sendfile() не изменяет текущее файловое смещение in_fd; иначе текущее файловое смещение изменяется для отражения количества прочитанных из in_fd байт. Если значение offset равно NULL, то данные будут прочитаны из in_fd начиная с текущего файлового смещения, и по окончании работы вызова файловое смещение будет обновлено. В count содержится количество байт, копируемых между файловыми дескрипторами. Значение in_fd должно описывать файл, который поддерживает операции типа mmap(2) (т.е., не сокет). В ядрах Linux до версии 2.6.33, значение out_fd должно указывать на сокет. Начиная с Linux 2.6.33 можно указывать любой файл. Если это обычный файл, то sendfile() изменит файловое смещение соответствующим образом.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Если пересылка прошла успешно, то возвращается количество переданных в out_fd байт. При ошибке возвращается -1, а переменной errno присваивается номер ошибки.

ОШИБКИ

EAGAIN
    Был выбран неблокирующий ввод-вывод с помощью O_NONBLOCK, но запись привела бы блокировке.

EBADF
    Входной файл не открыт для чтения или выходной файл не открыт для записи.

EFAULT
    Неправильный адрес.

EINVAL
    Неправильный или заблокированный дескриптор, или для in_fd недоступна операция типа mmap(2).

EIO Неизвестная ошибка при чтении in_fd.

ENOMEM
    Не хватает памяти для чтения in_fd.

ВЕРСИИ
Вызов sendfile() впервые появился в Linux 2.2. Файл заголовков <sys/sendfile.h> появился в glibc 2.1.

СООТВЕТСТВИЕ СТАНДАРТАМ
Отсутствует в POSIX.1-2001 и других стандартах. В других системах UNIX вызов sendfile() реализован с другими семантиками и прототипами. Не должен использоваться в переносимых программах.

ЗАМЕЧАНИЯ
Если вы планируете использовать sendfile() для отправки файлов через сокет TCP и вам нужно послать некоторые заголовочные данные перед содержимым файла, то обратите внимание на параметр TCP_CORK, описанный в tcp(7), он поможет минимизировать количество пакетов и оптимизировать производительность. В Linux 2.4 и более ранних, значение out_fd может также указывать на обычный файл, и sendfile() изменяет текущее смещение этого файла. Первоначальная версия Linux sendfile() не была приспособлена для работы с большими файловыми смещениями. В последствии в Linux 2.4 был добавлен вызов sendfile64() с более широким диапазоном значений аргумента offset. В glibc sendfile() представляет собой обёрточную функцию, которая делает незаметным разницу между версиями ядер. Приложение может попытаться воспользоваться read(2)/write(2), если вызов sendfile() завершится с ошибкой EINVAL или ENOSYS. Если out_fd ссылается на сокет или канал с поддержкой нулевого копирования, то вызывающие должны гарантировать, что переданные части файла, указываемого in_fd, останутся неизменёнными до тех пор, пока читающий на другом конце out_fd не закончит обрабатывать переданные данные. Специальный вызов Linux splice(2) поддерживает пересылку данных между произвольными файлами (например, между парой сокетов).

СМОТРИТЕ ТАКЖЕ
mmap(2), open(2), socket(2), splice(2)