socket(7) интерфейс сокетов Linux

ОБЗОР

#include <sys/socket.h>

sockfd = socket(int socket_family, int socket_type, int protocol);

ОПИСАНИЕ

В этой справочной странице описывается пользовательский интерфейс уровня сетевых сокетов Linux. Совместимый с сокетами BSD, он предоставляет унифицированный интерфейс между пользовательскими процессами и стеком сетевых протоколов в ядре. Модули протоколов группируются по семействам протоколов, такими, как AF_INET, AF_IPX и AF_PACKET, и типам сокетов, такими, как SOCK_STREAM или SOCK_DGRAM. Более подробная информация о семействах и типах приведена в socket(2).

Функции уровня сокетов

Эти функции используются пользовательскими процессами для отправки или приёма пакетов и выполнения других операций над сокетами. Более подробная информация приведена в соответствующих справочных страницах.

Вызов socket(2) создаёт сокет, connect(2) соединяет сокет с удалённым сокетным адресом, bind(2) привязывает сокет к локальному адресу, listen(2) сообщает сокету, что должны приниматься новые соединения, а accept(2) используется для получения нового сокета для нового входящего соединения. Вызов socketpair(2) возвращает два соединённых анонимных сокета (реализовано только для некоторых локальных семейств, например AF_UNIX).

Вызовы send(2), sendto(2) и sendmsg(2) отправляют данные в сокет, а recv(2), recvfrom(2) и recvmsg(2) принимают данные из сокета. Вызовы poll(2) и select(2) ожидают поступления данных или готовятся к передаче данных. Кроме того, для чтения и записи данных могут использоваться стандартные операции ввода-вывода: write(2), writev(2), sendfile(2), read(2) и readv(2).

Вызов getsockname(2) возвращает адрес локального сокета, а getpeername(2) возвращает адрес удалённого сокета. Вызовы getsockopt(2) и setsockopt(2) используются для установки или считывания параметров протокола или уровня сокетов. Вызов ioctl(2) может быть использован для установки или чтения некоторых других параметров.

Вызов close(2) используется для закрытия сокета. Вызов shutdown(2) закрывает части полнодуплексного сокетного соединения.

Перемещение (seeking), или вызовы pread(2) и pwrite(2) с ненулевой позицией, для сокетов не поддерживается.

Для сокетов возможно создание неблокирующего ввода/вывода путём установки в файловый дескриптор сокета флага O_NONBLOCK с помощью вызова fcntl(2). При этом все блокировавшие раньше операции, будут возвращать EAGAIN (операция должна быть повторена позднее); connect(2) возвратит ошибку EINPROGRESS. Пользователь может подождать наступления различных событий через poll(2) или select(2).

События ввода-вывода
СобытиеФлаг pollКогда происходит
ЧтениеPOLLIN Поступили новые данные
ЧтениеPOLLIN Установка соединения выполнена (для сокетов, ориентированных на соединение)
ЧтениеPOLLHUP Другая сторона инициировала запрос на разъединение
ЧтениеPOLLHUP Соединение разорвано (только для протоколов, ориентированных на соединение). Если производится запись в сокет, то также посылается сигнал SIGPIPE
ЗаписьPOLLOUT Сокет имеет достаточно места в буфере отправки для записи в него новых данных
Чтение/Запись POLLIN|
POLLOUT
Исходящий вызов connect(2) завершён
Чтение/ЗаписьPOLLERRПроизошла асинхронная ошибка
Чтение/ЗаписьPOLLHUPДругая сторона закрыла (shut down) одно направление
ИсключениеPOLLPRI Пришли неотложные данные. При этом посылается сигнал SIGURG

Альтернативе poll(2) и select(2) в ядре существует возможность информировать приложение о событиях с помощью сигнала SIGIO. Для этого необходимо установить с помощью fcntl(2) в файловом дескрипторе сокета флаг O_ASYNC, а также назначить с помощью sigaction(2) корректный обработчик сигнала SIGIO. Смотрите ниже раздел Сигналы.

Структуры адреса сокета

Каждый сокетный домен имеет свой формат сокетных адресов, выраженный в отдельной адресной структуре. Каждая из этих структур начинается с целочисленного поля «семейства» (с типом sa_family_t), в котором указывается тип адресной структуры. Это позволяет различным системным вызовам (например, connect(2), bind(2), accept(2), getsockname(2), getpeername(2)), которые являются общими для всех сокетов, определить домен конкретного сокетного адреса.

Для передачи сокетного адреса любого типа через программный интерфейс сокетов служит тип struct sockaddr. Целью данного типа является приведение типов сокетных адресов определённого домена к «общему» типу, что позволяет избежать предупреждений компилятора о несовпадении типов в вызовах API сокетов.

Также, программный интерфейс сокетов предоставляет тип данных struct sockaddr_storage. Данный тип удобен для размещения всех поддерживаемых структур сокетных адресов определённого домена; он достаточно большой и имеет корректное выравнивание (в частности, он позволяет хранить сокетные адреса IPv6). Для определения типа сокетного адреса, который хранится в структуре, служит следующее поле:

    sa_family_t ss_family;

Структура sockaddr_storage полезна для программ, которые должны работать с сокетными адресами единообразно (например, в программах, использующих одновременно сокетные адреса IPv4 и IPv6).

Параметры сокетов

Следующие параметры сокета могут быть установлены с помощью setsockopt(2) или считаны с помощью getsockopt(2) с уровнем сокета, равным SOL_SOCKET для всех сокетов:
SO_ACCEPTCONN
Определить, был или не был данный сокет помечен для прослушивания и приёма соединений с помощью listen(2). Возвращаемое значение 0 обозначает, что это не прослушивающий сокет. Значение 1 обозначает, что это прослушивающий сокет. Данный параметр сокета доступен только для чтения.
SO_BINDTODEVICE
Привязать сокет к определённому устройству, например, к «eth0», в соответствии с переданным именем интерфейса. Если имя является пустой строкой или длина параметра равна нулю, то привязка сокета к устройству будет удалена. В качестве параметра передаётся оканчивающаяся null строка переменной длины с именем интерфейса, максимальная длина которого не превышает IFNAMSIZ. Если сокет привязан к интерфейсу, то сокетом обрабатываются только пакеты этого интерфейса. Заметим, что это работает только для некоторых типов сокетов, в частности, для сокетов AF_INET. Это не поддерживается для сокетов пакетной передачи (для них используйте обычный bind(2)).

До Linux 3.8, данный параметр сокета можно было устанавливать, но нельзя прочитать с помощью getsockopt(2). Начиная с Linux 3.8 он доступен для чтения. Аргумент optlen должен содержать размер буфера, способного разместить имя устройства; рекомендуемое значение — IFNAMSZ байт. Реальная длина имени устройства возвращается обратно через аргумент optlen.

SO_BROADCAST
Задать или считать флаг широковещания. Если он установлен, то через датаграммные сокеты разрешено отправлять пакеты на широковещательный адрес. Этот параметр не действует на потоковые сокеты.
SO_BSDCOMPAT
Разрешить совместимость по ошибкам с BSD. Используется модулем протокола UDP в Linux версии 2.0 и 2.2. Если включено, то полученные UDP-сокетом ошибки ICMP не будут передаваться пользовательской программе. В последний версиях ядер поддержка этого параметра удалена: в Linux 2.4 он игнорируется, а в Linux 2.6 при использовании в программе для него генерируется предупреждение ядра (printk()). В Linux 2.0 также включён параметр совместимости по ошибкам с BSD и для неструктурированных сокетов (произвольное изменение заголовка, пропуск флага широковещательной передачи), но в Linux 2.2 это было удалено.
SO_DEBUG
Включить отладку сокета. Разрешено только процессам с мандатом CAP_NET_ADMIN или имеющим нулевой идентификатор эффективного пользователя.
SO_DOMAIN (начиная с Linux 2.6.32)
Получить доменный сокет в виде целого числа; пример возвращаемого значения: AF_INET6. Подробней смотрите в socket(2). Этот параметр сокета доступен только для чтения.
SO_ERROR
Получить и очистить ожидающую обработки ошибку сокета. Этот параметр сокета доступен только для чтения. Ожидает целое число.
SO_DONTROUTE
Не выполнять отправку через шлюз, посылать только на машины, соединенные напрямую. Тот же эффект может быть достигнут путём установки для сокета флага MSG_DONTROUTE во время вызова send(2). В качестве параметра ожидается целочисленный логический флаг.
SO_KEEPALIVE
Включить отправку «поддерживающих» (keep-alive) сообщений для сокетов, ориентированных на соединение. Ожидается целочисленный логический флаг.
SO_LINGER
Задать или считать параметр SO_LINGER. Аргументом является структура linger.

struct linger {
    int l_onoff;    /* задержка активна */
    int l_linger;   /* величина задержки в секундах */
};
Если этот параметр установлен, то close(2) или shutdown(2) не вернут управление до тех пор, пока не будут отправлены все сообщения в очереди сокета или до истечения времени задержки (linger). В противном случае вызовы вернут управление немедленно и закрытие будет произведено в фоновом режиме. Если сокет закрывается как часть вызова exit(2), то задержка всегда происходит в фоновом режиме.
SO_MARK (начиная с Linux 2.6.25)
Устанавливать метку на каждый пакет, отправленный через сокет (похоже на цель netfilter MARK, но для сокетов). Изменение метки можно использовать для маршрутизации на основе меток не задействуя netfilter или для фильтрации пакетов. Для установки этого параметра требуется мандат CAP_NET_ADMIN.
SO_OOBINLINE
Если включён этот параметр, то внепоточные данные помещаются непосредственно во входной поток данных. В противном случае внепоточные данные передаются только, если во время приёма установлен флаг MSG_OOB.
SO_PASSCRED
Включить или выключить приём управляющего сообщения SCM_CREDENTIALS. Подробней смотрите в unix(7).
SO_PEEK_OFF (начиная с Linux 3.4)
Этот параметр, который пока поддерживается только для сокетов unix(7), устанавливает значение «смещения выборки» (peek offset) для системного вызова recv(2), когда он используется с флагом MSG_PEEK.

Если этому параметру присваивается отрицательное значение (равен -1 для всех новых сокетов), то действует обычное правило: recv(2) с флагом MSG_PEEK выбирает данные из начала (front) очереди.

Если этому параметру присваивается положительное значение или ноль, то следующая выборка данных из очереди сокета произойдёт по байтовому смещению, определяемому значением этого параметра. В то же время, «смещение выборки» будет увеличено на количество байт, выбранных из очереди, то есть последовательные операции выборки возвращают следующие данные из очереди.

Если данные удалены из начала очереди с помощью вызова recv(2) (или подобного) без флага MSG_PEEK, то «смещение выборки» будет уменьшено на количество удалённых байт. Другими словами, приём данных без флага MSG_PEEK корректирует «смещение выборки» относительно поддерживаемого относительного положения данных в очереди, и последующая выборка возвратит данные, которые были бы получены, если бы данные не удалялись.

Для датаграммных сокетов, если «смещение выборки» указывает в середину пакета, то возвращаемые данные маркируются флагом MSG_TRUNC.

В следующем примере показано использование SO_PEEK_OFF. Предположим, в очереди потокового сокета есть входные данные:


    aabbccddeeff

Следующая последовательность вызовов recv(2) выполнила бы то, что описано в комментариях:

int ov = 4;        // установка смещения выборки равной 4
setsockopt(fd, SOL_SOCKET, SO_PEEK_OFF, &ov, sizeof(ov));
recv(fd, buf, 2, MSG_PEEK);  // выборка «cc»; смещение 6
recv(fd, buf, 2, MSG_PEEK);  // выборка «dd»; смещение 8
recv(fd, buf, 2, 0);         // выборка «aa»; смещение 6
recv(fd, buf, 2, MSG_PEEK);  // выборка «ee»; смещение 8
SO_PEERCRED
Получить учётные данные (credentials) стороннего процесса, соединённого с сокетом. Работает только для соединённых потоковых сокетов AF_UNIX, потоков AF_UNIX и датаграммных сокетных пар, созданных с помощью socketpair(2); смотрите unix(7). Возвращаются данные, которые были действительными на момент вызова connect(2) или socketpair(2). Аргументом является структура ucred; определите макрос тестирования свойств _GNU_SOURCE для получения определения этой структуры из <sys/socket.h>. Данный параметр сокета доступен только для чтения.
SO_PRIORITY
Установить определяемый протоколом приоритет для всех пакетов, отправляемых из этого сокета. Linux использует это значение для управления сетевыми очередями: пакеты с более высоким приоритетом могут быть обработаны раньше (в зависимости от выбранного для устройства способа постановки в очередь). Установка значения приоритета не из диапазона 0 до 6 требует мандата CAP_NET_ADMIN.
SO_PROTOCOL (начиная с Linux 2.6.32)
Получить протокол сокета в виде целого числа; пример возвращаемого значения: IPPROTO_SCTP. Подробней смотрите в socket(2). Этот параметр сокета доступен только для чтения.
SO_RCVBUF
Задать или получить максимальный размер буфера приёма сокета (в байтах). Ядро удваивает это значение (для пространства под учёт ресурсов (bookkeeping overhead)) при установке этого параметра с помощью setsockopt(2), и это удвоенное значение возвращается getsockopt(2). Значение по умолчанию устанавливается через файл /proc/sys/net/core/rmem_default, а максимальное возможное значение устанавливается через файл /proc/sys/net/core/rmem_max. Минимальное (удвоенное) значение для этого параметра равно 256.
SO_RCVBUFFORCE (начиная с Linux 2.6.14)
С помощью этого параметра сокета привилегированный (CAP_NET_ADMIN) процесс может выполнить ту же работу, что и с помощью SO_RCVBUF, но возможно превысить ограничение rmem_max.
SO_RCVLOWAT и SO_SNDLOWAT
Задать минимальное количество байт в буфере до которого уровень сокета будет отправлять данные протоколу (SO_SNDLOWAT) или получать их от пользователя (SO_RCVLOWAT). Начальное значение этих двух элементов равно 1. Для SO_SNDLOWAT значение в Linux изменить нельзя (setsockopt(2) завершает выполнение с ошибкой ENOPROTOOPT). Значение для SO_RCVLOWAT можно изменить начиная с Linux версии 2.4. Системные вызовы select(2) и poll(2) пока не учитывают настройку SO_RCVLOWAT в Linux, и помечают сокет как доступный для чтения даже когда доступен только 1 байт данных. Последующее чтение из сокета будет заблокировано до тех пор, пока не будет доступно SO_RCVLOWAT байт.
SO_RCVTIMEO и SO_SNDTIMEO
Задать время ожидания (при отправке или приёме) до генерации сообщения об ошибке. Аргументом является структура struct timeval. Если вводящая или выводящая функция блокируется на этот период времени, и данные был отправлены или получены, то возвращаемое значение этой функции будет равно количеству переданных данных; если данные не проходили и время ожидания истекло, то возвращается -1 и errno устанавливается в EAGAIN, EWOULDBLOCK или EINPROGRESS (для connect(2)) — также как, если был сокет был заблокирован. Если время ожидания установлено в 0 (по умолчанию), то операция не будет ждать. Время ожидания учитывается только в системных вызовах, которые выполняют ввод-вывод из сокета (например, read(2), recvmsg(2), send(2), sendmsg(2)); время ожидания не учитывается в select(2), poll(2), epoll_wait(2) и подобных.
SO_REUSEADDR
Указать, что правила проверки адресов, передаваемых с помощью вызова bind(2), должны позволять повторное использование локальных адресов. В случае с сокетами AF_INET это означает, что сокет может быть привязан (bind), за исключением случаев, когда активному слушающему сокету присвоен адрес. Если слушающий сокет привязан к INADDR_ANY с определённым портом, то к этому порту невозможно будет привязать любой локальный адрес. Аргументом является целочисленный логический флаг.
SO_REUSEPORT (начиная с Linux 3.9)
Разрешить многократную привязку сокета AF_INET или AF_INET6 к одинаковому адресу сокета. Данный параметр должен быть указан на каждом сокете (включая первый сокет) до вызова bind(2). Чтобы предотвратить захват порта все привязки процессов к одному адресу должны иметь один эффективный UID. Данный параметр можно применять к сокетам TCP и UDP.

Для сокетов TCP данный параметр позволяет accept(2) распределить нагрузку в многонитиевом сервере, назначая разные слушатели сокета в каждой нити. Это улучшает распределение нагрузки по сравнении с обычными методами, например с одной принимающей нитью accept(2), которая распределяет соединения, или с несколькими нитями, которые конкурируют за accept(2) единого сокета.

Для сокетов UDP использование данного параметра может улучшить распределение входящих датаграмм по нескольким процессам (или нитям) по сравнении с обычным методом с несколькими процессами, которые конкурируют при приёме датаграмм из единого сокета.

SO_RXQ_OVFL (начиная с Linux 2.6.33)
Указывает, что к принятым skbs должно быть прикреплено вспомогательное сообщение (cmsg) с беззнаковым 32-битным значением, которое обозначает количество пакетов, отброшенных сокетом между последним принятым пакетом и этим принятым пакетом.
SO_SNDBUF
Задать или считать максимальный размер буфера отправки сокета (в байтах). Ядро удваивает это значение (для пространства под учёт ресурсов (bookkeeping overhead)) при установке этого параметра с помощью setsockopt(2), и это удвоенное значение возвращается getsockopt(2). Значение по умолчанию устанавливается через файл /proc/sys/net/core/wmem_default, а максимальное возможное значение устанавливается через файл /proc/sys/net/core/wmem_max. Минимальное (удвоенное) значение для этого параметра равно 2048.
SO_SNDBUFFORCE (начиная Linux 2.6.14)
С помощью этого параметра сокета привилегированный (CAP_NET_ADMIN) процесс может выполнить ту же работу, что и с помощью SO_SNDBUF, но возможно превысить ограничение wmem_max.
SO_TIMESTAMP
Включить или выключить приём управляющего сообщения SO_TIMESTAMP. Управляющее сообщение метки времени посылается с уровнем SOL_SOCKET, а поле cmsg_data выражено структурой struct timeval, обозначающей время приёма последнего пакета, переданного пользователю в этом вызове. Подробней об управляющих сообщениях смотрите в cmsg(3).
SO_TYPE
Получить тип сокета в виде целого числа (например, SOCK_STREAM). Этот параметр сокета доступен только для чтения.
SO_BUSY_POLL (начиная с Linux 3.11)
Задаёт приблизительный интервал в микросекундах для задержки опроса при блокирующем приёме при отсутствии данных. Увеличение этого значения требует мандата CAP_NET_ADMIN. Значение по умолчанию данного параметра управляется через файл /proc/sys/net/core/busy_read.

Значение в файле /proc/sys/net/core/busy_poll определяет как долго select(2) и poll(2) задержат опрос, если они работают с сокетами с установленным SO_BUSY_POLL и отсутствуют события для извещения.

В обоих случаях опрос с задержкой (busy polling) будет завершён только, когда сокет примет все данные из сетевого устройства, которое поддерживает этот параметр.

Хотя опрос с задержкой может уменьшить время ожидания в некоторых приложениях, этим нужно пользоваться с осторожностью, так как его использование увеличит нагрузку на ЦП и энергопотребление.

Сигналы

При записи в сокет, ориентированный на соединение, который был выключен (shutdown) локальной или удалённой стороной, записывающему процессу посылается сигнал SIGPIPE и возвращается EPIPE. Сигнал не посылается, если вызов записи был сделан с флагом MSG_NOSIGNAL.

Если был произведён вызов fcntl(2) с FIOSETOWN или ioctl(2) с SIOCSPGRP, то при появлении событий ввода/вывода посылается сигнал SIGIO. Для определения сокета, в котором произошло событие, в обработчике можно воспользоваться вызовом poll(2) или select(2). Альтернативным способом (в Linux 2.2) является установка сигнала реального времени с помощью вызова fcntl(2) с F_SETSIG; будет вызван обработчик сигнала реального времени и в его структуре siginfo_t поле si_fd будет содержать значение файлового дескриптора. Дополнительная информация приведена в fcntl(2).

В некоторых случаях (например, при наличии доступа нескольких процессов к одному сокету) условие, вызвавшее SIGIO, может исчезнуть на момент обработки процессом сигнала. Если это происходит, то процесс должен подождать сигнала ещё какое-то время, так как Linux снова пошлёт его позже.

Интерфейсы /proc

Основные сетевые параметры сокета доступны через файлы в каталоге /proc/sys/net/core/.
rmem_default
устанавливаемый по умолчанию размер буфера приёма сокета (в байтах)
rmem_max
максимальный размер буфера приёма сокета (в байтах), который может установить пользователь с помощью параметра сокета SO_RCVBUF
wmem_default
устанавливаемый по умолчанию размер буфера отправки сокета (в байтах)
wmem_max
максимальный размер буфера отправки сокета (в байтах), который может установить пользователь с помощью параметра сокета SO_SNDBUF
message_cost и message_burst
фильтр корзины токенов, используемый для ограничения нагрузки сети предупреждающими сообщениями, вызванными внешними сетевыми событиями
netdev_max_backlog
максимальное количество пакетов в глобальной входящей очереди
optmem_max
максимальная длина вспомогательных данных и управляющих данных пользователя, таких, как iovec (для каждого сокета)

Вызовы ioctl

Следующие операции доступны через ioctl(2):

error = ioctl(ip_socket, ioctl_type, &value_result);
SIOCGSTAMP
Возвращает структуру struct timeval с меткой времени принятого последнего пакета, переданного пользователю. Это полезно для точного вычисления времени. Описание struct timeval приведено в setitimer(2). Данный ioctl нужно использовать только, если для сокета не задан параметр SO_TIMESTAMP. В противном случае возвращается метка времени последнего пакета, который был получен в то время, когда не был установлен SO_TIMESTAMP, или возвращается ошибка, если такой пакет вообще никогда не принимался (т.е. ioctl(2) возвращает -1 и устанавливает errno равной ENOENT).
SIOCSPGRP
Назначает процесс или группу процессов, которым будут посылаться сигналы SIGIO или SIGURG по окончании выполнения асинхронной операции или при появлении срочных данных. Аргумент является указателем на pid_t. Если аргумент отрицателен, то сигналы будут посылаться группе процессов c идентификатором, равным абсолютному значению аргумента. Если процесс не имеет мандата CAP_KILL или его эффективный идентификатор не равен нулю, то он может указывать только на себя или свою группу процессов.
FIOASYNC
Изменяет флаг O_ASYNC для включения или отключения асинхронного режима ввода/вывода сокета. В асинхронном режиме при появлении событий ввода/вывода посылается сигнал SIGIO или сигнал, установленный с помощью F_SETSIG.
Аргументом является целочисленный логический флаг. Данная операция аналогична вызову fcntl(2) с установленным флагом O_ASYNC.
SIOCGPGRP
Возвращает процесс или группу процессов, получающих сигналы SIGIO или SIGURG. Если такой процесс не задан, то возвращается нулевое значение.

Возможные операции fcntl(2):

FIOGETOWN
То же, что и вызов ioctl(2) SIOCGPGRP.
FIOSETOWN
То же, что и вызов ioctl(2) SIOCSPGRP.

ВЕРСИИ

Параметр SO_BINDTODEVICE появился в Linux 2.0.30. Параметр SO_PASSCRED появился в Linux 2.2. Интерфейсы /proc появились в Linux 2.2. Параметры SO_RCVTIMEO и SO_SNDTIMEO начали поддерживаться в Linux 2.3.41. До этого, времена ожидания были жёстко прописаны в настройках протокола и недоступны для чтения или записи.

ЗАМЕЧАНИЯ

В Linux предполагается, что половина буфера приёма/передачи используется для размещения внутренних структур ядра; поэтому соответствующие файлы /proc в два раза больше, чем кажутся.

В Linux разрешено повторное использование порта с параметром SO_REUSEADDR только, когда этот параметр установлен и в программе, уже выполнившей bind(2) и в программе, которая хочет использовать порт. Такое поведение отличается от некоторых реализаций (например, FreeBSD), в которых только последняя программа должна устанавливать параметр SO_REUSEADDR. Обычно, это отличие незаметно, так как, например, в серверных программах всегда устанавливают этот параметр.

ДЕФЕКТЫ

Параметры SO_ATTACH_FILTER и SO_DETACH_FILTER сокета CONFIG_FILTER не описаны. Рекомендуется использовать их с помощью библиотеки libpcap.