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
    Указанный адрес уже используется.

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

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

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

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

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

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

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

EINVAL
    Неправильный аргумент addrlen, или сокет не принадлежит семейству AF_UNIX.

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)