BIND(2)

ИМЯ
bind - привязывает имя к сокету

ОБЗОР
#include <sys/types.h>          /* См. ЗАМЕЧАНИЯ */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr,
         socklen_t addrlen);

ОПИСАНИЕ
После создания с помощью socket(2), сокет появляется в адресном пространстве (семействе адресов), но без назначенного адреса. bind() назначает адрес, заданный в addr, сокету, указываемому дескриптором файла sockfd. В аргументе addrlen задаётся размер структуры адреса (в байтах), на которую указывает addr. В силу традиции, эта операция называется «присваивание сокету имени».

Обычно, сокету типа SOCK_STREAM нужно назначить локальный адрес с помощью bind() до того, как он сможет принимать соединения (см. accept(2)). Правила, используемые при привязке имён, отличаются в разных семействах адресов. Подробности см. в соответствующем справочных страницах в разделе 7. Описание AF_INET находится в ip(7), AF_INET6 в ipv6(7), AF_UNIX в unix(7), AF_APPLETALK в ddp(7), AF_PACKET в packet(7), AF_X25 в x25(7), а AF_NETLINK в netlink(7). Реальная структура, передаваемая через addr, зависит от семейства адресов. Структура sockaddr определяется так:
struct sockaddr {
    sa_family_t sa_family;
    char        sa_data[14];
}
Единственным смыслом этой структуры является преобразование указателя структуры, передаваемого в addr, чтобы избежать предупреждений компилятора. См. ПРИМЕР ниже.

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

ОШИБКИ

EACCES
    Адрес защищён, или пользователь не является суперпользователем.

EADDRINUSE
    Указанный адрес уже используется.

EADDRINUSE
    (доменные сокеты Интернета) В структуре адреса сокета указан номер порта равный нулю, но при попытке привязаться к эфемеридному порту, было определено, что все номера в диапазоне эфемеридных портов уже используются. Смотрите обсуждение /proc/sys/net/ipv4/ip_local_port_range в ip(7).

EBADF
    sockfd не является правильным дескриптором.

EINVAL
    Сокет уже привязан к адресу.

EINVAL
    Некорректное значение addrlen, или в addr указан некорректный адрес для этого доменного сокета.

ENOTSOCK
    sockfd является дескриптором файла, а не сокета.

Следующие ошибки только для сокетов домена UNIX (AF_UNIX):

EACCES
    Поиск запрещён из-за одного из частей префикса пути (см. также path_resolution(7)).

EADDRNOTAVAIL
    Запрошен несуществующий интерфейс или запрашиваемый адрес не является локальным.

EFAULT
    addr указывает вне адресного пространства, доступного пользователю.

ELOOP
    При определении addr превышено количество переходов по символьной ссылке.

ENAMETOOLONG
    Аргумент addr слишком большой.

ENOENT
    Файл не существует.

ENOMEM
    Недостаточное количество памяти ядра.

ENOTDIR
    Компонент в префиксе пути не является каталогом.

EROFS
    Попытка создания inode сокета на файловой системе, доступной только для чтения.

СООТВЕТСТВИЕ СТАНДАРТАМ
SVr4, 4.4BSD, POSIX.1-2001 (bind() впервые появился в 4.2BSD).

ЗАМЕЧАНИЯ
В POSIX.1-2001 не требуется включение <sys/types.h>, и этот заголовочный файл не требуется в Linux. Однако, некоторые старые (BSD) реализации требуют данный файл, и в переносимых приложениях для предосторожности, вероятно, он будет включён. Третий аргумент bind() в действительности имеет тип int (в 4.x BSD, libc4 и libc5). Ситуация несколько запуталась с введением POSIX для него отдельного типа socklen_t, также используемого в glibc. См. также accept(2).

ДЕФЕКТЫ
Не описываются возможности, связанные с работой прозрачных прокси.

ПРИМЕР
Пример использования bind() с сокетами домена Internet можно найти в getaddrinfo(3). Следующий пример показывает как привязать потоковый сокет к домену UNIX (AF_UNIX) и принимать соединения:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MY_SOCK_PATH "/somepath"
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
    int sfd, cfd;
    struct sockaddr_un my_addr, peer_addr;
    socklen_t peer_addr_size;
    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd == -1)
        handle_error("socket");
    memset(&my_addr, 0, sizeof(struct sockaddr_un));
                        /* Очистка структуры */
    my_addr.sun_family = AF_UNIX;
    strncpy(my_addr.sun_path, MY_SOCK_PATH,
            sizeof(my_addr.sun_path) - 1);
    if (bind(sfd, (struct sockaddr *) &my_addr,
            sizeof(struct sockaddr_un)) == -1)
        handle_error("bind");
    if (listen(sfd, LISTEN_BACKLOG) == -1)
        handle_error("listen");
    /* Теперь мы можем принимать входящие соединения по одному
       с помощью accept(2) */
    peer_addr_size = sizeof(struct sockaddr_un);
    cfd = accept(sfd, (struct sockaddr *) &peer_addr,
                 &peer_addr_size);
    if (cfd == -1)
        handle_error("accept");
    /* Код обработки входящего соединения(й)... */
    /* Если имя пути сокета, MY_SOCK_PATH, больше не требуется,
       то его нужно удалить с помощью unlink(2) или remove(3) */
}

СМОТРИТЕ ТАКЖЕ
accept(2), connect(2), getsockname(2), listen(2), socket(2), getaddrinfo(3), getifaddrs(3), ip(7), ipv6(7), path_resolution(7), socket(7), unix(7)