ОБЗОР
#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 байт. Заметим, что при успешном выполнении вызов sendfile() может записать меньше байт, чем запрашивалось; вызывающий должен быть готов повторить вызов, если останутся не отправленные байты. Также смотрите ЗАМЕЧАНИЯ.В случае ошибки возвращается -1 и значение errno устанавливается соответствующим образом.
ОШИБКИ
- EAGAIN
- Был выбран неблокирующий ввод-вывод с помощью O_NONBLOCK, но запись привела бы блокировке.
- EBADF
- Входной файл не открыт для чтения или выходной файл не открыт для записи.
- EFAULT
- Неправильный адрес.
- EINVAL
- Неправильный или заблокированный дескриптор, или для in_fd недоступна операция типа mmap(2) или значение count отрицательно.
- EINVAL
- У out_fd установлен флаг O_APPEND. Пока это не поддерживается в sendfile().
- EIO
- Неизвестная ошибка при чтении in_fd.
- ENOMEM
- Не хватает памяти для чтения in_fd.
- EOVERFLOW
- Значение count слишком велико, операция вернула бы результат, превышающий максимальный размер входного или выходного файла.
- ESPIPE
- Значение offset не равно NULL, но для входного файла не работает seek(2).
ВЕРСИИ
Вызов sendfile() впервые появился в Linux 2.2. Файл заголовков <sys/sendfile.h> появился в glibc 2.1.СООТВЕТСТВИЕ СТАНДАРТАМ
Отсутствует в POSIX.1-2001 и других стандартах.В других системах UNIX вызов sendfile() реализован с другими семантиками и прототипами. Не должен использоваться в переносимых программах.
ЗАМЕЧАНИЯ
Вызов sendfile() передаст не больше 0x7ffff000 (2 147 479 552) байт, возвращая число байт, переданных на самом деле (это утверждение справедливо как к 32-битным, так и к 64-битным системам).Если вы планируете использовать sendfile() для отправки файлов через сокет TCP и вам нужно послать некоторые заголовочные данные перед содержимым файла, то обратите внимание на параметр TCP_CORK, описанный в tcp(7), он поможет минимизировать количество пакетов и оптимизировать производительность.
В Linux 2.4 и более ранних, значение out_fd может также указывать на обычный файл; эта возможность была удалена в ядрах Linux 2.6.x, но возвращена в 2.6.33.
Первоначальная версия 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) поддерживает пересылку данных между произвольными файлами (например, между парой сокетов).