Меню

При возникновении ошибки системный вызов listen возвращает

Системный вызов listen()

Системный вызов listen() является первым из еще неизвестных нам вызовов, применяемым на TCP–сервере. В его задачу входит перевод TCP–сокета в пассивное (слушающее) состояние и создание очередей для порождаемых при установлении соединения присоединенных сокетов, находящихся в состоянии не полностью установленного соединения и полностью установленного соединения. Для этого вызов имеет два параметра: дескриптор TCP–сокета и число, определяющее глубину создаваемых очередей.

Схема установления TCP соединения

Рис.
15-16.8.
Схема установления TCP соединения

Системный вызов listen()

Прототип системного вызова

#include <sys/types.h>
#include <sys/socket.h> 
int listen(int sockd, int backlog);

Описание системного вызова

Системный вызов listen используется сервером, ориентированным на установление связи путем виртуального соединения, для перевода сокета в пассивный режим и установления глубины очереди для соединений.

Параметр sockd является дескриптором созданного ранее сокета, который должен быть переведен в пассивный режим, т. е. значением, которое вернул системный вызов socket() . Системный вызов listen требует предварительной настройки адреса сокета с помощью системного вызова bind() .

Параметр backlog определяет максимальный размер очередей для сокетов, находящихся в состояниях полностью и не полностью установленных соединений.

Возвращаемое значение

Системный вызов возвращает значение 0 при нормальном завершении и значение -1 при возникновении ошибки.

Последний параметр на разных UNIX-подобных операционных системах и даже на разных версиях одной и той же системы может иметь различный смысл. Где-то это суммарная длина обеих очередей, где-то он относится к очереди не полностью установленных соединений (например, Linux до версии ядра 2.2) где-то – к очереди полностью установленных соединений (например, Linux, начиная с версии ядра 2.2), где-то – вообще игнорируется.

Системный вызов accept()

Системный вызов accept() позволяет серверу получить информацию о полностью установленных соединениях. Если очередь полностью установленных соединений не пуста, то он возвращает дескриптор для первого присоединенного сокета в этой очереди, одновременно удаляя его из очереди. Если очередь пуста, то вызов ожидает появления полностью установленного соединения. Системный вызов также позволяет серверу узнать полный адрес клиента, установившего соединение. У вызова есть три параметра: дескриптор слушающего сокета, через который ожидается установление соединения; указатель на структуру, в которую при необходимости будет занесен полный адрес сокета
клиента, установившего соединение; указатель на целую переменную, содержащую максимально допустимую длину этого адреса. Как и в случае вызова recvfrom() , последний параметр является модернизируемым, а если нас не интересует, кто с нами соединился, то вместо второго и третьего параметров можно указать значение NULL.

Системный вызов accept()

Прототип системного вызова

#include <sys/types.h>
#include <sys/socket.h> 
int accept(int sockd, 
    struct sockaddr *cliaddr, 
    int *clilen);

Описание системного вызова

Системный вызов accept используется сервером, ориентированным на установление связи путем виртуального соединения, для приема полностью установленного соединения .

Параметр sockd является дескриптором созданного и настроенного сокета, предварительного переведенного в пассивный (слушающий) режим с помощью системного вызова listen() .

Системный вызов accept требует предварительной настройки адреса сокета с помощью системного вызова bind() .

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

Параметр clilen содержит указатель на целую переменную, которая после возвращения из вызова будет содержать фактическую длину адреса клиента. Заметим, что перед вызовом эта переменная должна содержать максимально допустимое значение такой длины. Если параметр cliaddr имеет значение NULL, то и параметр clilen может иметь значение NULL.

Возвращаемое значение

Системный вызов возвращает при нормальном завершении дескриптор присоединенного сокета, созданного при установлении соединения для последующего общения клиента и сервера, и значение -1 при возникновении ошибки.

Пример простого TCP-сервера

Рассмотрим программу 15–16-4.c, реализующую простой TCPсервер для сервиса echo.

/* Пример простого TCP-сервера для сервиса echo */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
void main()
{
    int sockfd, newsockfd; /* Дескрипторы для 
слушающего и присоединенного сокетов */
    int clilen; /* Длина адреса клиента */
    int n; /* Количество принятых символов */
    char line[1000]; /* Буфер для приема информации */
    struct sockaddr_in servaddr, cliaddr; /* Структуры 
        для размещения полных адресов сервера и 
        клиента */
    /* Создаем TCP-сокет */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        perror(NULL);
        exit(1);
    }
    /* Заполняем структуру для адреса сервера: семейство
    протоколов TCP/IP, сетевой интерфейс – любой, номер 
    порта 51000. Поскольку в структуре содержится 
    дополнительное не нужное нам поле, которое должно 
    быть нулевым, побнуляем ее всю перед заполнением */
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family= AF_INET;
    servaddr.sin_port= htons(51000);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    /* Настраиваем адрес сокета */
    if(bind(sockfd, (struct sockaddr *) &servaddr, 
    sizeof(servaddr)) < 0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }
    /* Переводим созданный сокет в пассивное (слушающее) 
    состояние. Глубину очереди для установленных 
    соединений описываем значением 5 */
    if(listen(sockfd, 5) < 0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }
    /* Основной цикл сервера */
    while(1){
        /* В переменную clilen заносим максимальную
        длину ожидаемого адреса клиента */
        clilen = sizeof(cliaddr);
        /* Ожидаем полностью установленного соединения
        на слушающем сокете. При нормальном завершении 
        у нас в структуре cliaddr будет лежать полный 
        адрес клиента, установившего соединение, а в 
        переменной clilen – его фактическая длина. Вызов
        же вернет дескриптор присоединенного сокета, через
        который будет происходить общение с клиентом. 
        Заметим, что информация о клиенте у нас в
        дальнейшем никак не используется, поэтому 
        вместо второго и третьего параметров можно 
        было поставить значения NULL. */
        if((newsockfd = accept(sockfd, 
        (struct sockaddr *) &cliaddr, &clilen)) < 0){
            perror(NULL);
            close(sockfd);
            exit(1);
        }
        /* В цикле принимаем информацию от клиента до
        тех пор, пока не произойдет ошибки (вызов read()
        вернет отрицательное значение) или клиент не
        закроет соединение (вызов read() вернет 
        значение 0). Максимальную длину одной порции 
        данных от клиента ограничим 999 символами. В
        операциях чтения и записи пользуемся дескриптором
        присоединенного сокета, т. е. значением, которое
        вернул вызов accept().*/
        while((n = read(newsockfd, line, 999)) > 0){
            /* Принятые данные отправляем обратно */
            if((n = write(newsockfd, line, 
            strlen(line)+1)) < 0){
                perror(NULL);
                close(sockfd);
                close(newsockfd);
                exit(1);
            }
        }
    /* Если при чтении возникла ошибка – завершаем работу */
    if(n < 0){
            perror(NULL);
            close(sockfd);
            close(newsockfd);
            exit(1);
        }
        /* Закрываем дескриптор присоединенного сокета и
        уходим ожидать нового соединения */
        close(newsockfd);
    }
}


Листинг
15-16.4.
Программа 15–16-4.c . Пример простого TCP-сервера для сервиса echo.

Наберите и откомпилируйте программу. Запустите ее на выполнение. Модифицируйте текст программы TCP-клиента (программа 15–16-3.c ), заменив номер порта с 7 на 51000. Запустите клиента с другого виртуального терминала или с другого компьютера и убедитесь, что клиент и сервер взаимодействуют корректно.

listen(2)
слушать соединения на сокете

ОБЗОР

#include <sys/types.h> /* Смотрите ЗАМЕЧАНИЯ */
#include <sys/socket.h>


int listen(int sockfd, int backlog);

ОПИСАНИЕ

Вызов listen() помечает сокет, указанный в sockfd как пассивный, то
есть как сокет, который будет использоваться для приёма запросов входящих
соединений с помощью accept(2).

Аргумент sockfd является файловым дескриптором, который ссылается на
сокет типа SOCK_STREAM или SOCK_SEQPACKET.

Аргумент backlog задает максимальный размер, до которого может расти
очередь ожидающих соединений у sockfd. Если приходит запрос на
соединение, а очередь полна, то клиент может получить ошибку с указание
ECONNREFUSED или, если низлежащий протокол поддерживает повторную
передачу, запрос может быть игнорирован, чтобы попытаться соединиться
позднее.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а
errno устанавливается в соответствующее значение.

ОШИБКИ

EADDRINUSE
Другой сокет уже слушает на этом же порту.
EADDRINUSE
(доменные сокеты Интернета) Сокет, указанный sockfd, ранее не был
привязан к адресу и при попытке привязать его к эфемеридному порту, было
определено, что все номера в диапазоне эфемеридных портов уже
используются. Смотрите обсуждение /proc/sys/net/ipv4/ip_local_port_range
в ip(7).
EBADF
Аргумент sockfd не является допустимым файловым дескриптором.
ENOTSOCK
Файловый дескриптор sockfd указывает не на каталог.
EOPNOTSUPP
Тип сокета не поддерживает операцию listen().

СООТВЕТСТВИЕ СТАНДАРТАМ

POSIX.1-2001, POSIX.1-2008, 4.4BSD (вызов listen() впервые появился в
4.2BSD).

ЗАМЕЧАНИЯ

Для принятия соединений должны быть выполнены следующие шаги:

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

В POSIX.1 не требуется включение <sys/types.h>, и этот
заголовочный файл не требуется в Linux. Однако, для некоторых старых
реализаций (BSD) требует данный файл, и в переносимых приложениях для
предосторожности, вероятно, лучше его указать.

Поведение аргумента backlog на TCP-сокетах изменилось в Linux 2.2. Теперь
вместо количества неоконченных запросов на соединение он задает размер
очереди для полностью (completely) установленных соединений, ожидающих,
пока процесс примет их. Максимальный размер очереди для неполных сокетов
может быть задан через /proc/sys/net/ipv4/tcp_max_syn_backlog. Когда
разрешено использование syncookies, логический максимальный размер
отсутствует и эта настройка игнорируется. Подробности см. в tcp(7).

Если значение аргумента backlog больше, чем значение
/proc/sys/net/core/somaxconn, то он без предупреждения обрезается до этой
величины; значение по умолчанию в данном файле равно 128. В ядрах до версии
2.4.25, этот предел указывался в константе SOMAXCONN и имел значение 128.

������������� ������� ��������� ��������� ���������� (man-��)

listen ()


  • listen (1) ( Solaris man: ������� � ���������� ��������� ����������������� ������ )
  • listen (2) ( FreeBSD man: ��������� ������ )
  • >> listen (2) ( ������� man: ��������� ������ )
  • listen (2) ( Linux man: ��������� ������ )
  • listen (3) ( Solaris man: ������������ ������ )
  • listen (3) ( POSIX man: ������������ ������ )
  • listen (7) ( Linux man: ����������� � ���������� )
  •  

    ���

    listen — ������� ���������� �� ������
     

    �����

    #include <sys/socket.h>

    int listen(int s, int backlog);

     

    ��������

    ��� ����, ����� ��������� ����������, ������� ����� ������� ����� � �������
    socket(2),

    ����� �������� ���������� ��������� �������� ���������� � ������
    ������ ������� � �������
    listen,

    � ����� ��������
    accept(2)

    �� ���� ��������� ����� ����������.
    ��������� �����
    listen

    �������� ������ � ������� ����
    SOCK_STREAM

    ���
    SOCK_SEQPACKET.

    ��������
    backlog

    ������ ������������ �����, �� ������� ����� ����� ������� ���������
    ����������. ���� �������� ������ �� ����������, � ������� �����, ��
    ������ ������� ������
    ECONNREFUSED

    ���, ���� ��������������� �������� ������������ ��������� ��������,
    ������ ����� ���� �����������, ����� ���������� �������� �� ���������
    ������.
     

    ���������

    ��������� ���������
    backlog

    �� TCP-������� ���������� � Linux 2.2. ������ ������ ����������
    ������������ �������� �� ���������� �� ������ ������ ������� ���
    ���������

    ������������� ����������, ���������, ���� ������� ������
    ��. ������������ ������ ������� ��� ������������ ������� ����� ����
    ������, ��������� sysctl
    tcp_max_syn_backlog.

    ����� ��������� ������������� syncookies, ���������� ������������
    ����� ����������� � ��������� ����� sysctl ������������.
    ��.
    tcp(7)

    �� ���������� �����������.

    ������������ ��������

    � ������ ������ ������������ ����. ��� ������ ������������ -1, �
    errno

    ��������������� ������� �������.

    ������

    EADDRINUSE

    ������ ����� ��� ������� �� ���� �� �����.
    EBADF

    ��������
    s

    �� �������� ���������� ������������.

    ENOTSOCK

    ��������
    s

    �� �������� �������.

    EOPNOTSUPP

    ��� ������ �� ������������ ��������
    listen.

     

    ������������ ����������

    Single Unix, 4.4BSD, �������� POSIX 1003.1g. �����
    listen

    ������� �������� � 4.2BSD.
     

    ������ ����������

    ���� ����� ����� ���
    AF_INET,

    � ��������
    backlog

    ������, ��� ���������
    SOMAXCONN

    (128 � Linux 2.0 & 2.2), �� �� ��������� ���������� ��
    SOMAXCONN.

    �� ����������� �� ��� �������� � ������������ �����������, ������ ���
    BSD � ��������� ţ ������� ������������ ������ ������� �� 5.
     

    ������ �����

    accept(2),

    connect(2),

    socket(2)

     

    �������

    Copyright (C) Alexey Mahotkin <alexm@hsys.msk.ru> 1999,
    ������ ���������� <corochoone@perm.ru> 2003


     

    Index

    ���
    �����
    ��������
    ���������
    ������������ ��������
    ������
    ������������ ����������
    ������ ����������
    ������ �����
    �������

    Перевод сокета в пассивное состояние. Создание очереди соединений

    listenQ

    accept().

    write()

    close()

    Ожидание
    желающих установить соединение.
    Установка соединения. Создание нового
    потокового сокета

    г*-

    Ожидание
    получения

    информации.
    Чтение информации

    Обработка
    информаии

    Отправление
    ответа

    Окончание
    соединения

    connect()

    Передача
    информации серверу

    write()

    і

    Ожидание
    получения информации. Чтение информации

    read()

    Окончание
    соединения

    Рис.
    14-15.7.
    Схема
    взаимодействия клиента и сервера для
    протокола TCP

    Установление
    логического соединения. Системный вызов
    connectQ

    Среди
    системных вызовов со стороны клиента
    появляется только один новый — connect
    ().
    Системный вызов connect
    ()
    при работе с ТСР-сокетами служит для
    установления логического соединения
    со стороны клиента. Вызов connect
    ()
    скрывает внутри себя настройку сокета
    на выбранный системой порт и произвольный
    сетевой интерфейс (по сути дела, вызов
    bind()
    с нулевым номером порта и IP-адресом
    INADDR_ANY).
    Вызов
    блокируется до тех пор, пока не будет
    установлено логическое соединение, или
    пока не пройдет определенный промежуток
    времени, который может регулироваться
    системным администратором.

    Для
    установления соединения необходимо
    задать три параметра: дескриптор
    активного сокета, через который будет
    устанавливаться соединение, полный
    адрес сокета сервера и его длину.

    Системный
    вызов
    connect()

    Прототип
    системного вызова

    Mnclude
    <sys/types.h> Mnclude <sys/socket.h>

    int
    connect(int sockd, struct sockaddr *servaddr, int addrlen);

    Описание
    системного вызова

    Системный
    вызов
    connect
    служит
    для организации связи клиента с сервером.
    Чаще всего он используется для установления
    логического соединения, хотя может быть
    применен и при связи с помощью датаграмм
    (
    connectionless).
    Данное описание не является полным
    описанием системного вызова, а
    предназначено только для использования
    в нашем курсе. Полную информацию можно
    найти в
    UNIX
    Manual.

    Параметр
    sockd
    является
    дескриптором созданного ранее
    коммуникационного узла, т. е. значением,
    которое вернул системный вызов
    socket
    ().

    Параметр
    servaddr
    представляет
    собой адрес структуры, содержащей
    информацию о полном адресе сокета
    сервера. Он имеет тип указателя на
    структуру-шаблон
    struct
    sockaddr,
    которая
    должна быть конкретизирована в зависимости
    от используемого семейства протоколов
    и заполнена перед вызовом.

    Параметр
    addrlen
    должен
    содержать фактическую длину структуры,
    адрес которой передается в качестве
    второго параметра. Эта длина меняется
    в зависмости от семейства протоколов
    и различается даже в пределах одного
    семейства протоколов (например, для
    UNIX
    Domain).

    При
    установлении виртуального соединения
    системный вызов не возвращается до его
    установления или до истечения
    установленного в системе времени —
    timeout.
    При использовании его в
    connectionless
    связи вызов возвращается немедленно.

    Возвращаемое
    значение

    Системный
    вызов возвращает значение
    0
    при
    нормальном завершении и отрицательное
    значение, если в процессе его выполнения
    возникла ошибка.

    Пример
    программы
    TCP-клиента

    Рассмотрим
    пример — программу 14—15-З.с. Это простой
    ТСР-кли-ент, обращающийся к стандартному
    системному сервису echo.
    Стандартный
    сервис принимает от клиента текстовую
    датаграмму и, не изменяя ее, отправляет
    обратно. За сервисом зарезервирован
    номер порта 7. Заметим, что это порт 7 TCP
    — не путать с портом 7 UDP
    из примера в разделе «Пример программы
    UDP-клиента»!
    Для правильного запуска программы
    необходимо указать символьный IP-адрес
    сетевого интерфейса компьютера, к
    сервису которого требуется обратиться,
    в качестве аргумента командной строки,
    например:

    a.out
    192.168.253.12

    Для
    того чтобы подчеркнуть, что после
    установления логического соединения
    клиент и сервер могут обмениваться
    информацией неоднократно, клиент трижды
    запрашивает текст с экрана, отсылает
    его серверу и печатает полученный ответ.
    Ниже представлен текст программы.

    /*
    Простой пример TCP-клиента
    для сервиса echo
    */

    #include
    <sys/types.h>

    #include
    <sys/socket.h>

    #include
    <netinet/in.h>

    #include
    <arpa/inet.h>

    #include
    <string.h>

    #include
    <stdio.h>

    #include
    <errno.h>

    #include
    <unistd.h>

    void
    main(int argc, char **argv)

    {

    int
    sockfd;
    /* Дескриптор сокета */

    int
    n;
    /* Количество переданных или прочитанных

    символов
    */ int
    i;
    /* Счетчик цикла */

    char
    sendline[1000],recvline[1000]
    ; /* Массивы для отсылаемой и принятой
    строки */ struct
    sockaddr_in
    servaddr;
    /* Структура для

    адреса
    сервера */ /* Сначала проверяем наличие
    второго аргумента в командной строке.
    При его отсутствии прекращаем работу
    */ if(argc
    != 2){

    printf(«Usage:
    a.out
    <IP
    address>n»);

    exit(l);

    }

    /*
    Обнуляем символьные массивы */
    bzero(sendline,1000);
    bzero(recvline,1000);
    /* Создаем ТСР-сокет */

    if((sockfd
    = socket(PF_INET, SOCK_STREAM, 0)) < 0){ perror(NULL); /* Печатаем
    сообщение
    об
    ошибке
    */

    exit
    (1) ;

    }

    /*
    Заполняем структуру для адреса сервера:
    семейство протоколов TCP/IP, сетевой
    интерфейс — из аргумента командной
    строки, номер порта 7.
    Поскольку в структуре содержится
    дополнительное не нужное нам поле,
    хоторое должно быть нулевым, перед
    заполнением обнуляем ее всю
    */
    bzero(&servaddr,
    sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port =
    htons(51000);

    іf(inet_aton(argv[1],
    kservaddr.sin_addr) == 0){ printf(«Invalid IP addressn»);
    close(sockfd); exit(1);

    }

    /*
    Устанавливаем логическое соединение
    через созданный сокет с сокетом сервера,
    адрес которого мы занесли в структуру
    */

    if
    (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))
    < 0){

    perror(NULL);

    close(sockfd);

    exit(1);

    }

    /*
    Три раза в цикле вводим строку с
    клавиатуры, отправляем ее серверу и
    читаем полученный ответ */ for(i=0;
    i<3;
    i++){

    printf(«String
    => «); fflush(stdin);

    fgets(sendline,
    1000, stdin)• if( (n = write(sockfd, sendline, strlen(sendline)+1))
    < 0){

    perror(«Can’t
    writen»);

    close(sockfd);

    exit(1)
    ;

    }

    if
    ( (n = read(sockfd,recvline, 999)) < 0){ perror(«Can1t
    readn»); close(sockfd); exit(1) ;

    )

    printf(«%s»,
    recvline);

    }

    /*
    Завершаем
    соединение
    */ close(sockfd);

    }

    Наберите
    и откомпилируйте программу. Перед
    запуском узнайте
    у своего системного администратора,
    запущен
    ли в системе стандартный TCP-сервис
    echo
    и,
    если нет, попросите это сделать. Запустите
    программу с запросом к сервису своего
    компьютера, к сервисам других компьютеров.
    Если в качестве IP-адреса
    указать несуществующий адрес или адрес
    выключенной машины, то программа сообщит
    об ошибке при работе вызова connect
    ()
    (правда, возможно, придется подождать
    окончания time-out’a).
    При задании адреса компьютера, на котором
    не работает сервис echo,
    об
    ошибке станет известно сразу же. Протокол
    TCP
    является надежным протоколом. Если
    логическое соединение установить не
    удалось, то отправитель будет знать об
    этом.

    Как
    происходит установление виртуального
    соединения

    Протокол
    TCP
    является надежным дуплексным протоколом.
    С точки зрения пользователя работа
    через протокол TCP
    выглядит как обмен информацией через
    поток данных. Внутри сетевых частей
    операционных систем поток данных
    отправителя нарезается на пакеты данных,
    которые, собственно, путешествуют по
    сети и на машине-получателе вновь
    собираются в выходной поток данных. В
    лекции 4
    речь
    шла о том, каким образом может обеспечиваться
    надежность передачи информации в
    средствах связи, использующих в своей
    основе передачу пакетов данных. В
    протоколе TCP
    используются приемы нумерации передаваемых
    пакетов и контроля порядка их получения,
    подтверждения о приеме пакета со стороны
    получателя и насчет контрольных сумм
    по передаваемой информации. Для
    правильного порядка получения пакетов
    получатель должен знать начальный номер
    первого пакета отправителя. Поскольку
    связь является дуплексной, и в роли
    отправителя пакетов данных могут
    выступать обе взаимодействующие стороны,
    они до передачи пакетов данных должны
    обменяться, по крайней мере, информацией
    об их начальных номерах. Согласование
    начальных номеров происходит по
    инициативе клиента при выполнении
    системного вызова connect
    ().

    Для
    такого согласования клиент посылает
    серверу специальный пакет информации,
    который принято называть SYN
    (от слова synchronize
    — синхронизировать). Он содержит, как
    минимум, начальный номер для пакетов
    данных, который будет использовать
    клиент. Сервер должен подтвердить
    получение пакета SYN
    от клиента и отправить ему свой пакет
    SYN
    с начальным номером для пакетов данных,
    в виде единого пакета с сегментами SYN
    и АСК (от слова acknowledgement
    — подтверждение). В ответ клиент пакетом
    данных АСК должен подтвердить прием
    пакета данных от сервера.

    Описанная
    выше процедура, получившая название
    трехэтапного
    рукопожатия (
    threeway
    handshake),
    схематично
    изображена на рисунке 14-15.8. При приеме
    на машине-сервере пакета SYN,
    направленного на пассивный (слушающий)
    сокет, сетевая часть создает операционной
    системе копию этого сокета — присоединенный
    сокет — для последующего общения,
    отмечая его как сокет сне полностью
    установленным соединением. После приема
    от клиента пакета АСК этот сокет
    переводится в состояние полностью
    установленного соединения, и тогда он
    готов к дальнейшей работе с использованием
    вызовов read
    ()
    и write
    ().

    Системный
    вызов
    listen()

    Системный
    вызов listen
    ()
    является первым из еще неизвестных нам
    вызовов, применяемым на TCP-сервере.
    В его задачу входит перевод ТСР-сокета
    в пассивное (слушающее) состояние и
    создание очередей для порождаемых при
    установлении соединения присоединенных
    сокетов, находящихся в состоянии не
    полностью установленного соединения
    и полностью установленного соединения.
    Для этого вызов имеет два параметра:
    дескриптор ТСР-сокета и число, определяющее
    глубину создаваемых очередей.

    Клиент

    Сервер

    Начало
    вызова connectQ

    Создание
    присоединенного сокета в очереди не
    полностью установленных соединений

    Перевод
    присоединенного сокета в очередь
    полностью установленных соединений

    Рис.
    14-15.8. Схема установления ТСР-соединения

    Системный
    вызов
    listen()

    Прототип
    системного вызова

    #include
    <sys/types.h>

    #include
    <sys/socket.h>

    int
    listen{int
    sockd,
    int
    backlog);

    Описание
    системного вызова

    Системный
    вызов
    listen
    используется
    сервером, ориентированным на установление
    связи путем виртуального соединения,
    для перевода сокета в пассивный режим
    и установления глубины очереди для
    соединений.

    Параметр
    sockd
    является
    дескриптором созданного ранее сокета,
    который должен быть переведен в пассивный
    режим, т. е. значением, которое вернул
    системный вызов
    socket
    ().
    Системный
    вызов
    1
    i
    st
    en
    требует
    предварительной настройки адреса сокета
    с помощью системного вызова
    bind
    ().

    Параметр
    backlog
    определяет
    максимальный размер очередей для
    сокетов, находящихся в состояниях
    полностью и не полностью установленных
    соединений.

    Возвращаемое
    значение

    Системный
    вызов возвращает значение
    0
    при
    нормальном завершении и значение
    -1
    при
    возникновении ошибки.

    Последний
    параметр на разных UNIX-подобных
    операционных системах и даже на разных
    версиях одной и той же системы может
    иметь различный смысл. Где-то это
    суммарная длина обеих очередей, где-то
    он относится к очереди не полностью
    установленных соединений (например,
    Linux
    до версии ядра 2.2) где-то — к очереди
    полностью установленных соединений
    (например, Linux,
    начиная с версии ядра 2.2), где-то — вообще
    игнорируется.

    Системный
    вызов
    accept()

    Системный
    вызов accept
    ()
    позволяет серверу получить информацию
    о полностью установленных соединениях.
    Если очередь полностью установленных
    соединений не пуста, то он возвращает
    дескриптор для первого присоединенного
    сокета в этой очереди, одновременно
    удаляя его из очереди. Если очередь
    пуста, то вызов ожидает появления
    полностью установленного соединения.
    Системный вызов также позволяет серверу
    узнать полный адрес клиента, установившего
    соединение. У вызова есть три параметра:
    дескриптор слушающего сокета, через
    который ожидается установление
    соединения; указатель на структуру, в
    которую при необходимости будет занесен
    полный адрес сокета клиента, установившего
    соединение; указатель на целую переменную,
    содержащую максимально допустимую
    длину этого адреса. Как и в случае вызова
    recvfromO,
    последний
    параметр является модернизируемым, а
    если нас не интересует, кто с нами
    соединился, то вместо второго и третьего
    параметров можно указать значение NULL.

    Системный
    вызов
    accept()

    Прототип
    системного вызова

    #include
    <sys/types.h> #include <sys/socket.h>

    int
    accept(int sockd, struct sockaddr *cliaddr, int *clilen);

    Описание
    системного вызова

    Системный
    вызов
    accept
    используется
    сервером, ориентированным на установление
    связи путем виртуального соединения,
    для приема полностью установленного
    соединения.

    Параметр
    sockd
    является
    дескриптором созданного и настроенного
    сокета, предварительного переведенного
    в пассивный (слушающий) режим с помощью
    системного вызова
    listen
    ().

    Системный
    вызов
    accept
    требует
    предварительной настройки адреса сокета
    с помощью системного вызова
    bind().

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

    Параметр
    с
    1
    i
    1
    en
    содержит
    указатель на целую переменную, которая
    после возвращения из вызова будет
    содержать фактическую длину адреса
    клиента.
    Заметим,
    что перед вызовом эта переменная должна
    содержать
    максимально
    допустимое значение такой длины. Если
    параметр
    cliaddr
    имеет
    значение
    NULL,
    то
    и параметр
    clilen
    может
    иметь значение
    NULL.

    Возвращаемое
    значение

    Системный
    вызов возвращает при нормальном
    завершении дескриптор присоединенного
    сокега, созданного при установлении
    соединения для последующего общения
    клиента и сервера, и значение
    -1
    при
    возникновении ошибки.

    Пример
    простого ТСР-сервера

    Рассмотрим
    программу 14—15-4.С,
    реализующую
    простой ТСР-сер-вер для сервиса echo:

    /*
    Пример простого TCP-сервера
    для сервиса echo
    */

    #include
    <sys/types.h>

    #include
    <sys/socket.h>

    #include
    <netinet/in.h>

    #include
    <arpa/inet.h>

    #include
    <string.h>

    #include
    <stdio.h>

    #include
    <errno.h>

    #include
    <unistd.h>

    void
    main()

    {

    int
    sockfd, newsockfd; /* Дескрипторы
    для

    слушающего
    и присоединенного сокетов */

    int
    clilen;
    /* Длина адреса клиента */

    int
    п; /* Количество принятых символов */

    char
    line[1000];
    /* Буфер для приема информации */

    struct
    sockaddr_in servaddr, cliaddr; /* Структуры

    для
    размещения полных адресов сервера и

    клиента
    */ /* Создаем
    ТСР-сокет
    */

    if((sockfd
    = socket(AF_INET, SOCK_STREAM, 0)) < 0){ perror(NULL); exit(1);

    /*
    Заполняем структуру для адреса сервера:
    семейство протоколов TCP/IP, сетевой
    интерфейс — любой, номер порта 51000.
    Поскольку
    в структуре содержится дополнительное
    не нужное нам поле, которое должно быть
    нулевым, обнуляем ее всю перед заполнением
    */
    bzero(&servaddr,
    sizeof(servaddr));
    servaddr.sin_family=
    AF_INET;
    servaddr.sin_port=
    htons(51000);
    servaddr.sin_addr.s_addr
    = htonl(INADDR_ANY);
    /* Настраиваем адрес сокета */

    іf(bind(sockfd,
    (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0){

    perror(NULL);

    close(sockfd);

    exit
    (1) ;

    }

    /*
    Переводим
    созданный
    сокет в пассивное (слушающее) состояние.
    Глубину очереди для установленных
    соединений описываем значением 5 */ if
    (listenfsockfd,
    5) < 0){

    perror(NULL);

    close(sockfd);

    exit
    (1) ;

    }

    /*
    Основной цикл сервера */ while(l){

    /*
    В переменную clilen
    заносим максимальную длину ожидаемого
    адреса клиента */ clilen
    = sizeof(cliaddr);

    /*
    Ожидаем полностью установленного
    соединения на слушающем сокете. При
    нормальном завершении у нас в структуре
    cliaddr
    будет лежать полный адрес клиента,
    установившего соединение, а в переменной
    clilen
    — его фактическая длина. Вызов же вернет
    дескриптор присоединенного сокета,
    через который будет происходить общение
    с клиентом. Заметим, что информация о
    клиенте у нас в дальнейшем никак не
    используется, поэтому вместо второго
    и третьего параметров можно было
    поставить значения NULL.
    */
    if((newsockfd = accept(sockfd,

    (struct
    sockaddr *) &cliaddr, &clilen)) < 0){

    perror(NULL);
    close(sockfd); exit(1);

    }

    /*
    В цикле принимаем информацию от клиента
    до тех пор, пока не произойдет ошибки
    (вызов read()
    вернет отрицательное значение) или
    клиент не закроет соединение (вызов
    read()
    вернет значение 0). Максимальную длину
    одной порции данных от клиента ограничим
    999 символами. В
    операциях чтения и записи пользуемся
    дескриптором присоединенного сокета,
    т. е. значением, которое вернул вызов
    accept().*/

    while((n
    = read(newsockfd,
    line,
    999)) > 0){ /* Принятые данные отправляем
    обратно */ if((n
    = write(newsockfd,
    line,
    strlen(line)+1))
    < 0){

    perror(NULL);

    closet
    sockfd) ;

    close(newsockfd);

    exit(1)
    ;

    }

    }

    /*
    Если при чтении возникла ошибка —
    завершаем работу */ if(п
    < 0){

    perror(NULL);

    close(sockfd);

    close(newsockfd);

    exit(1);

    }

    /*
    Закрываем дескриптор присоединенного
    сокета и уходим ожидать нового соединения
    */ close(newsockfd);

    }

    }

    Наберите
    и откомпилируйте программу. Запустите
    ее на выполнение. Модифицируйте текст
    программы ТСР-клиента (программа 14—
    15-З.с), заменив номер порта с 7 на 51000.
    Запустите клиента с другого виртуального
    терминала или с другого компьютера и
    убедитесь, что клиент и сервер
    взаимодействуют корректно.

    Создание
    программы с параллельной обработкой
    запросов клиентов

    В
    приведенном выше примере сервер
    осуществлял последовательную обработку
    запросов от разных клиентов. При таком
    подходе клиенты могут подолгу простаивать
    после установления соединения, ожидая
    обслуживания. Поэтому обычно применяется
    схема псевдопараллельной обработки
    запросов. После приема установленного
    соединения сервер порождает процесс-ребенок,
    которому и поручает дальнейшую работу
    с клиентом. Процесс-родитель закрывает
    присоединенный сокет и уходит на ожидание
    нового соединения. Схематично организация
    такого сервера изображена на рис.
    14-15.9.

    Напишите,
    откомпилируйте и запустите такой
    параллельный сервер. Убедитесь в его
    работоспособности. Не забудьте о
    необходимости удаления зомби-процессов.

    Применение
    интерфейса сетевых вызовов для других
    семейств протоколов.
    UNIX
    Domain
    протоколы. Файлы типа «сокет»

    Рассмотренный
    нами интерфейс умеет работать не только
    со стеком протоколов TCP/IP, но и с другими
    семействами протоколов. При этом
    требуется лишь незначительное изменение
    написанных с его помощью программ.
    Рассмотрим действия, которые необходимо
    выполнить для модернизации написанных
    для TCP/IP программ под другое семейство
    протоколов:

    1. Изменяется
      тип сокета, поэтому для его точной
      спецификации нужно задавать другие
      параметры в системном вызове socket
      ().

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

    3. Описание
      типов данных и предопределенных констант
      будет находиться в других include-файлах,
      поэтому потребуется заменить include-файлы
      <netinet/in.h>
      и
      <агра/inet.h>
      на
      файлы, относящиеся к выбранному семейству
      протоколов.

    4. Может
      измениться способ вычисления фактической
      длины полного адреса сокета и указания
      его максимального размера.

    И
    все!!!

    Давайте
    подробнее рассмотрим эти изменения на
    примере семейства UNIX
    Domain
    протоколов. Семейство UNIX
    Domain
    протоколов предназначено для общения
    локальных процессов с использованием
    интер фейса системных вызовов. Оно
    содержит один потоковый и один
    дата-граммный протокол. Никакой сетевой
    интерфейс при этом не используется, а
    вся передача информации реально
    происходит через адресное пространство
    ядра операционной системы. Многие
    программы, взаимодействующие и с
    локальными, и с удаленными процессами
    (например, Х-ЭДпс!оу8),
    для
    локального общения используют этот
    стек протоколов.

    Процесс-ребенок

    Закрытие
    пассивного сокета

    Ожидание
    получения информации. Чтение информации

    Обработка
    информации

    Отправление
    ответа

    Завершение
    соединения. Закрытие присоединенного
    сокета

    closeQ

    read
    ()

    writeQ

    cIose()

    Закрытие
    присоединенного сокета

    closeQ

    Окончание
    работы

    exit()

    Рис.
    14-15.9. Схема работы ТСР-сервера с
    параллельной обработкой запросов

    Поскольку
    общение происходит в рамках одной
    вычислительной системы, в полном адресе
    сокета его удаленная часть отсутствует.
    В качестве адресного пространства
    портов — локальной части адреса —
    выбрано адресное пространство, совпадающее
    с множеством всех допустимых имен файлов
    в файловой системе.

    При
    этом в качестве имени сокета требуется
    задавать имя несуществующего еще файла
    в директории, к которой у вас есть права
    доступа как на запись, так и на чтение.
    При настройке адреса (системный вызов
    bind())
    под этим именем будет создан файл типа
    «сокет» — последний еще неизвестный
    нам тип файла. Этот файл для сокетов
    играет роль файла-метки типа FIFO
    для именованных pip’oe.
    Если на вашей машине функционируют
    Х-Windows,
    то вы сможете обнаружить такой файл в
    директории с именем /стр/
    . Xll-unix

    это файл типа «сокет», служащий для
    взаимодействия локальных процессов с
    оконным сервером.

    Для
    хранения полного адреса сокета
    используется структура следующего
    вида, описанного в файле <sys/un.
    h>:

    struct
    sockaddr __un{

    short
    sun_family; /* Избранное
    семейство

    протоколов
    — всегда AF_UNIX
    */ char
    sun_path[108];
    /* Имя файла типа «сокет» */

    };

    Выбранное
    имя файла мы будем копировать внутрь
    структуры, используя функциюstrcpy().

    Фактическая
    длина полного адреса сокета, хранящегося
    в структуре с именем my_addr,
    может
    быть вычислена следующим образом:
    sizeof(short)+strlen(my_addr.sun_path).
    В Linux
    для этих целей можно использовать
    специальный макрос языка С:

    SUN_LEN(struct
    sokaddr_un*)

    Ниже
    приведены тексты переписанных подсемейство
    UNIX
    Domain
    протоколов клиента и сервера для сервиса
    echo
    (программы
    14— 15-5.c
    и
    14—15-6.с), общающиеся через датаграммы.
    Клиент использует сокет с именем АААА
    в
    текущей директории, а сервер — сокет с
    именем ВВВВ.
    Как
    следует из описания типа данных, эти
    имена (полные или относительные) не
    должны по длине превышать 107 символов.
    Комментарии даны лишь для изменений по
    сравнению с программами 14—15l.c
    и 14— 15-2.c.

    /*
    A simple echo UNIX Domain datagrairan server */ #include
    <sys/types.h> #include <sys/socket.h>

    #include
    <sys/un.h> /* Новый
    include-файл
    вместо

    netinet/in.h
    и
    arpa/inet.h */ #include <string.h> #include <stdio.h>
    #include <errno.h> #include <unistd.h> int main() {

    int
    sockfd; int clilen, n; char line[1000];

    struct
    sockaddr_un servaddr, cliaddr; /* новый

    тип
    данных под адреса сокетов */ if((sockfd
    = socket(AF_UNIX,
    SOCK_DGRAM,
    0)) < 0) /* Изменен тип семейства протоколов
    */

    {

    perror(NULL);
    exit (1) ;

    }

    bzero(&servaddr,
    sizeof(servaddr));

    servaddr.sun_family
    = AF_UNIX; /* Изменен
    тип

    семейства
    протоколов и имя поля в структуре */
    strcpy(servaddr.sun_path,»ВВВВ»);
    /* Локальный

    адрес
    сокета сервера — ВВВВ
    — в текущей
    директории */ if(bind(sockfd,
    (struct
    sockaddr
    *) &servaddr,
    SUN_LEN(&servaddr))
    < 0) /* Изменено вычисление

    фактической
    длины адреса */

    {

    perror(NULL);
    close(sockfd);
    exit(1);

    }

    while(l)
    {

    clilen
    = sizeof(struct sockaddr_un); /* Изменено

    вычисление
    максимальной
    длины
    для
    адреса
    клиента
    */ if((n = recvfrom(sockfd, line, 999, 0, (struct sockaddr *)
    &cliaddr, &clilen)) < 0){

    perror(NULL);

    close(sockfd)
    ;

    exit(1);

    }

    if(sendto(sockfd,
    line, strlen(line), 0, (struct sockaddr *) &cliaddr, clilen) <
    0){

    perror(NULL);
    close(sockfd); exit(1);

    }

    }

    return
    0;

    }

    /*
    A simple echo UNIX Domain datagram client */ #include <sys/types.h>
    #include <sys/socket.h>

    #include
    <sys/un.h> /* Новый
    include-файл
    вместо

    netinet/in.h
    и
    arpa/inet.h */ #include <string.h> #include <stdio.h>
    #include <errno.h> #include <unistd.h>

    int
    main()
    /* Аргументы командной строки не нужны,
    так как сервис является локальным, и не
    нужно

    указывать,
    к какой машине мы обращаемся с запросом
    */

    {

    int
    sockfd; int n, len;

    char
    sendline[1000], recvline[1000];

    struct
    sockaddr_un servaddr, cliaddr; /* новый

    тип
    данных под адреса сокетов */

    if((sockfd
    = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)

    /*
    Изменен тип семейства протоколов */

    {

    perror(NULL);
    exit(1);

    }

    bzero(kcliaddr,
    sizeof(cliaddr));

    cliaddr.sun_family=
    AF_UNIX;
    /* Изменен тип

    семейства
    протоколов и имя поля в структуре */
    strcpy(cliaddr.sun_path,»АААА»);/*
    Локальный адрес

    сокета
    клиента — АААА — в текущей директории */
    if(bind(sockfd,
    (struct
    sockaddr
    *) kcliaddr,
    SUN_LEN(kcliaddr))
    < 0) /* Изменено вычисление

    фактической
    длины адреса */

    {

    perror(NULL);

    close(sockfd);
    exit(1)
    ;

    }

    bzero(&servaddr,
    si zeof(servaddr));

    servaddr.sun_family
    = AF_UNIX; /* Изменен
    тип

    семейства
    протоколов и имя поля в структуре */
    strcpy(servaddr.sun_path,»ВВВВ»);
    /* Локальный адрес

    сокета
    сервера — ВВВВ — в текущей директории */
    printf(«String
    => «); fgets(sendline,
    1000,
    stdin);

    if(sendto(sockfd,
    sendline,
    strlen(sendline)+1,
    0,
    (struct
    sockaddr
    *) &servaddr,
    SUN_LEN(&servaddr))
    < 0)
    /*
    Изменено вычисление фактической длины
    адреса */

    {

    perror(NULL);
    close(sockfd); exit (1) ;

    }

    if((n
    = recvfrom(sockfd, recvline, 1000,
    0,
    (struct
    sockaddr *) NULL, NULL)) < 0){

    perror(NULL);

    close(sockfd);

    exit(1)
    ;

    }

    recvline[n]
    = 0
    ;
    printf(«%s»,
    recvline); close(sockfd); return 0;

    }

    Наберите
    программы, откомпилируйте их и убедитесь
    в их работоспособности.

    Создание
    потоковых клиента и сервера для стека
    UNIX
    Domain
    протоколов

    По
    аналогии с программами в предыдущем
    примере модифицируйте тексты программ
    TCP
    клиента и сервера для сервиса echo
    (программы
    14—15-3.с и 14— 15-4.с) для потокового общения
    в семействе UNIX
    Domain
    протоколов. Откомпилируйте их и убедитесь
    в их правильном функционировании.

    Литература

    [Bach,
    1986] [СС1ТТ, 1991]

    [Denning,
    1996] [DoD, 1993] [DTI, 1991]

    [Intel,
    1989] [Linnaes,1789]

    [Ritchie,1984]

    [Silberschatz,
    2002]

    [Stevens,
    1990]

    [Axo,
    2001]

    [Баурн,1986]
    [Беляков,
    1991]

    [Блэк,
    2001] [Брамм, 1990] [Вахалия, 2003] [Дейтел, 1987]
    [Дунаев, 1996]

    Bach
    M.J. The design of the UNIX Operating System.— Prentice-Hall, 1986.

    Security
    Architecture for Open Systems Interconnection for CCITT Applications.
    Recommendations X.800. CCITT. -Geneva. 1991.

    Peter
    J. Denning. Before memory was virtual, Draft, June 6th 1996, at
    http://cne.gmu.edu/pjd/PUBS/bvm.pdf.
    Department of Defense. Trusted Computer System Evaluation Criteria. —
    DoD 5200.28, STD. 1993. Department of Trade and Industry. Information
    Technology Security Evaluation Criteria (ITSEC). Harmonized Criteria
    of France — Germany — the Netherlands — the United Kingdom. —
    London. 1991. i486™ Microprocessor, Intel Corporation, 1989.
    Linnaeus. Karl, Systema naturae, 13lh
    ed., t. 1-3 — Lugduni, 1789-96

    Ritchie
    D.M., The Evolution of the Unix Time-sharing System. // AT&T Bell
    Laboratories Technical Journal 63

    No.
    6, Part 2, October 1984 — pp. 1577-93. Silberschatz A., P.B.Galvin,
    Operating System Concepts, 6th edition. — John Willey & Sons,
    2002.

    Stevens
    R. W,
    Unix Network Programming — Prentice Hall, Inc., 1990, First
    edition.

    Axo
    В., Хопкрофт Д., Ульман Д. Структуры данных
    и алгоритмы. — М.: Вильяме, 2001. Баурн С.
    Операционная система UNIX.
    — М.: Мир. 1986. Беляков М.И., Рабовер Ю.И.,
    Фридман А.Л. Мобильная операционная
    система. — М.:, Радио и связь, 1991.

    Блэк
    У.
    Интернет: протоколы безопасности.
    Учебный курс. — Спб.: Издательский дом
    Питер, 2001. Брамм П., Брамм Д. Микропроцессор
    80386 и его применение. — М., Мир, 1990.

    Вахалия
    Ю. UNIX
    изнутри. — Спб.: Издательский дом Питер,
    2003.

    Дейтел
    Г.
    Введение в операционные системы. — М.:
    Мир, 1987.

    Дунаев
    С.
    Unix. System V.
    Release 4.2. — М.:
    Диалог
    МИФИ,
    1996.

    [Казаринов,
    1990] Казаринов Ю.М., Номоконов В.М.,
    Подклетнов Г.С., Филиппов Ф.М.
    Микропроцессорный комплекс К1810. — М.:
    Высшая школа, 1990.[Кастер, 1996] Кастер
    Хелен. Основы Windows
    NT
    и NTFS.
    — М.:

    Русская
    редакция.1996. [Керниган, 1992] Керниган Б.
    В., Пайк P.
    UNIX
    — универсальная среда программирования.
    — М.: Финансы и статистика. 1992. [Коффрон,
    1983] Коффрон Дж. Технические средства
    микропроцессорных систем. — М.: Мир,
    1983.[Кузнецов] Кузнецов С.Д. Операционная
    система UNIX.
    http://www.citforum.rU/operating_systems/unix/contents.s
    html.

    [Олифер,
    2000] Олифер В.Г., Олифер Н.А. Новые технологии
    и оборудование IP-сетей.
    — Спб.: BHV,
    2000. [Олифер, 2001] Олифер В.Г., Олифер Н.А.
    Сетевые операционные системы. — Спб.:
    Издательский дом Питер, 2001. [Олифер,
    2002] Олифер В.Г., Олифер Н.А. Компьютерные
    сети. Принципы, технологии, протоколы.
    — Спб.: Издательский дом Питер, 2002.
    [Снейдер, 2001] Снейдер Й. Эффективное
    программирование TCP/IP. — Издательский
    дом Питер, 2001. [Соломон, 2001] Соломон Д.,
    Руссинович М. Внутреннее устройство
    Microsoft
    Windows
    2000. — СПб: Издательский дом Питер,
    М.: Русская редакция, 2001. [Стивене, 2002]
    Стивене У.
    UNIX:
    Взаимодействие процессов. —

    СПб:
    Издательский дом Питер, 2002. [Стивене,
    2003] Стивене У.
    UNIX:
    разработка сетевых приложений. —

    СПб:
    Издательский дом Питер, 2003. [Столлингс,
    2001] Столлингс В., Операционные системы.
    — М.:

    Вильяме,
    2001.

    [Таненбаум,
    2002] Таненбаум Э. Современные операционные

    системы.
    — СПб.: Издательский дом Питер, 2002.
    [Таненбаум, 2003] Таненбаум Э. Компьютерные
    сети. — СПб.:

    Издательский
    дом Питер, 2003. [Таненбаум II, 2003] Таненбаум
    Э., Ван Стеен М. Распределенные системы.
    Принципы и парадигмы. — СПб.:

    Издательский
    дом Питер, 2003. [Робачевский, 1999] Робачевский
    А. Операционная система UNIX.
    — Спб.: BHV,
    1999.

    [Цикритис,
    1977] Цикритис Д., Бернстайн Ф. Операционные
    системы. — М.: Мир. 1977.

    Серия
    «Основы информационных технологий»

    Серия
    учебных пособий «Основы информационных
    технологий» открыта в издательстве
    Интернет-Университета Информационных
    Технологий в 2003 году и предполагает
    издание более 100 книг. В настоящее время
    в ее рамках вышли более 30
    учебных пособий по самым разным
    направлениям информационных и
    коммуникационных технологий. Авторами
    этой серии являются известные профессора
    и преподаватели ведущих российских
    вузов, а также представители компьютерного
    бизнеса и академической среды. Ряд
    учебных курсов создаются при активном
    участии и поддержке ведущих отечественных
    и иностранных компаний, а также
    общественных организаций и коммерческих
    ассоциаций в области информационных
    технологий.

    Книги
    серии

    1. Основы
    Web-технологий,

    П.Б.
    Храмцови др., 2003, 512 с, ISBN
    5-9556-0001-9.

    2. Основы
    сетей передачи данных,

    В.Г.
    Олифер, Н.А. Олифер, 2005, 176 с, ISBN
    5-9556-0035-3.

    4.5. Функция listen

    Функция listen вызывается только сервером TCP и выполняет два действия.

    1. Когда сокет создается с помощью функции socket, считается, что это активный сокет, то есть клиентский сокет, который запустит функцию connect. Функция listen преобразует неприсоединенный сокет в пассивный сокет, запросы на подключение к которому начинают приниматься ядром. В терминах диаграммы перехода между состояниями TCP (см. рис. 2.4) вызов функции listen переводит сокет из состояния CLOSED в состояние LISTEN.

    2. Второй аргумент этой функции задает максимальное число соединений, которые ядро может помещать в очередь этого сокета.

    #include <sys/socket.h>

    int listen(int sockfd, int backlog);

    Возвращает: 0 в случае успешного выполнения, -1 в случае ошибки

    Эта функция обычно вызывается после функций socket и bind. Она должна вызываться перед вызовом функции accept.

    Чтобы уяснить смысл аргумента backlog, необходимо понять, что для данного прослушиваемого сокета ядро поддерживает две очереди:

    1. Очередь не полностью установленных соединений (incomplete connection queue), содержащую запись для каждого сегмента SYN, пришедшего от клиента, для которого сервер ждет завершения трехэтапного рукопожатия TCP. Эти сокеты находятся в состоянии SYN_RCVD (см. рис. 2.4).

    2. Очередь полностью установленных соединений (complete connection queue), содержащую запись для каждого клиента, с которым завершилось трехэтапное рукопожатие TCP. Эти сокеты находятся в состоянии ESTABLISHED (см. рис. 2.4).

    На рис. 4.2 представлены обе эти очереди для прослушиваемого сокета.

    Рис. 4.2. Две очереди, поддерживаемые прослушиваемым сокетом TCP

    Когда в очередь не полностью установленных соединений добавляется новая запись, параметры прослушиваемого сокета копируются на создаваемое соединение. Механизм создания соединения полностью автоматизирован, и процесс сервера в нем не участвует. На рис. 4.3 показан обмен пакетами во время установления соединения с использованием этих очередей.

    Рис. 4.3. Обмен пакетами в процессе установления соединения с применением очередей

    Когда от клиента приходит сегмент SYN, TCP создает новую запись в очереди не полностью установленных соединений, а затем отвечает вторым сегментом трехэтапного рукопожатия, посылая сегмент SYN вместе с сегментом ACK, подтверждающим прием клиентского сегмента SYN (см. раздел 2.6). Эта запись останется в очереди не полностью установленных соединений, пока не придет третий сегмент трехэтапного рукопожатия (клиентский сегмент ACK для сегмента сервера SYN) или пока не истечет время жизни этой записи. (В реализациях, происходящих от Беркли, время ожидания (тайм-аут) для элементов очереди не полностью установленных соединений равно 75 с.) Если трехэтапное рукопожатие завершается нормально, запись переходит из очереди не полностью установленных соединений в конец очереди полностью установленных соединений. Когда процесс вызывает функцию accept (о которой мы поговорим в следующем разделе), ему возвращается первая запись из очереди полностью установленных соединений, а если очередь пуста, процесс переходит в состояние ожидания до появления записи в ней.

    Есть несколько важных моментов, которые нужно учитывать при работе с этими очередями.

    ? Аргумент backlog функции listen исторически задавал максимальное суммарное значение для обеих очередей.

    ? Беркли-реализации включают поправочный множитель для аргумента backlog, равный 1,5 [111, с. 257], [128, с. 462]. Например, при типичном значении аргумента backlog = 5 в таких системах допускается до восьми записей в очередях, как показано в табл. 4.6.

    ПРИМЕЧАНИЕ

    Формального определения аргумента backlog никогда не существовало. В руководстве 4.2BSD сказано, что «он определяет максимальную длину, до которой может вырасти очередь не полностью установленных соединений». Многие руководства и даже POSIX копируют это определение дословно, но в нем не говорится, в каком состоянии должно находится соединение — в состоянии SYN_RCVD, ESTABLISHED (до вызова accept), или же в любом из них. Определение, приведенное выше, относится к реализации Беркли 4.2BSD, и копируется многими другими реализациями.

    ПРИМЕЧАНИЕ

    Причина возникновения этого множителя теряется в истории [57]. Но если мы рассматриваем backlog как способ задания максимального числа установленных соединений, которые ядро помещает в очередь прослушиваемого сокета (об этом вскоре будет рассказано), этот множитель нужен для учета не полностью установленных соединений, находящихся в очереди [8].

    ? Не следует задавать нулевое значение аргументу backlog, поскольку различные реализации интерпретируют это по-разному (см. табл. 4.6). Некоторые реализации допускают помещение в очередь одного соединения, в то время как в других вообще невозможно помещать соединения в очередь. Если вы не хотите, чтобы клиенты соединялись с вашим прослушиваемым сокетом, просто закройте прослушиваемый сокет.

    ? Если трехэтапное рукопожатие завершается нормально (то есть без потерянных сегментов и повторных передач), запись остается в очереди не полностью установленных соединений на время одного периода обращения (round-trip time, RTT), какое бы значение ни имел этот параметр для конкретного соединения между клиентом и сервером. В разделе 14.4 [112] показано, что для одного веб-сервера средний период RTT оказался равен 187 мс. (Чтобы редкие большие числа не искажали картину, здесь использована медиана, а не обычное среднее арифметическое по всем клиентам.)

    ? Традиционно в примерах кода всегда используется значение backlog, равное 5, поскольку это было максимальное значение, которое поддерживалось в системе 4.2BSD. Это было актуально в 80-х, когда загруженные серверы могли обрабатывать только несколько сотен соединений в день. Но с ростом Сети (WWW), когда серверы обрабатывают миллионы соединений в день, столь малое число стало абсолютно неприемлемым [112, с. 187–192]. Серверам HTTP необходимо намного большее значение аргумента backlog, и новые ядра должны поддерживать такие значения.

    ПРИМЕЧАНИЕ

    В настоящее время многие системы позволяют администраторам изменять максимальное значение аргумента backlog.

    ? Возникает вопрос: какое значение аргумента backlog должно задавать приложение, если значение 5 часто является неадекватным? На этот вопрос нет простого ответа. Серверы HTTP сейчас задают большее значение, но если заданное значение является в исходном коде константой, то для увеличения константы требуется перекомпиляция сервера. Другой способ — принять некоторое значение по умолчанию и предоставить возможность изменять его с помощью параметра командной строки или переменной окружения. Всегда можно задавать значение больше того, которое поддерживается ядром, так как ядро должно обрезать значение до максимального, не возвращая при этом ошибку [128, с. 456].

    Мы приводим простое решение этой проблемы, изменив нашу функцию-обертку для функции listen. В листинге 4.1[1] представлен действующий код. Переменная окружения LISTENQ позволяет переопределить значение по умолчанию.

    Листинг 4.1. Функция-обертка для функции listen, позволяющая переменной окружения переопределить аргумент backlog

    //lib/wrapsock.c

    137 void

    138 Listen(int fd, int backlog)

    139 {

    140  char *ptr;

    141  /* может заменить второй аргумент на переменную окружения */

    142  if ((ptr = getenv(«LISTENQ»)) != NULL)

    143   backlog = atoi(ptr);

    144  if (listen(fd, backlog) < 0)

    145   err_sys(«listen error»);

    146 }

    ? Традиционно в руководствах и книгах утверждалось, что помещение фиксированного числа соединений в очередь позволяет обрабатывать случай загруженного серверного процесса между последовательными вызовами функции accept. При этом подразумевается, что из двух очередей больше записей будет содержаться, вероятнее всего, в очереди полностью установленных соединений. Но оказалось, что для действительно загруженных веб-серверов это не так. Причина задания большего значения backlog в том, что очередь не полностью установленных соединений растет по мере поступления сегментов SYN от клиентов; элементы очереди находятся в состоянии ожидания завершения трехэтапного рукопожатия.

    ? Если очереди заполнены, когда приходит клиентский сегмент SYN, то TCP игнорирует приходящий сегмент SYN [128, с. 930–931] и не посылает RST. Это происходит потому, что состояние считается временным, и TCP клиента должен еще раз передать свой сегмент SYN, для которого в ближайшее время, вероятно, найдется место в очереди. Если бы TCP сервера послал RST, функция connect клиента сразу же возвратила бы ошибку, заставив приложение обработать это условие, вместо того чтобы позволить TCP выполнить повторную передачу. Кроме того, клиент не может увидеть разницу между сегментами RST в ответе на сегмент SYN, означающими, что на данном порте нет сервера либо на данном порте есть сервер, но его очереди заполнены.

    ПРИМЕЧАНИЕ

    Некоторые реализации отправляют сегмент RST в описанной выше ситуации, что некорректно по изложенным выше причинам. Если вы не пишете клиент специально для работы с подобным сервером, лучше всего игнорировать такую возможность. Ее учет при кодировании клиента снизит его устойчивость и увеличит нагрузку на сеть, если окажется, что порт действительно не прослушивается сервером.

    ? Данные, которые приходят после завершения трехэтапного рукопожатия, но до того, как сервер вызывает функцию accept, должны помещаться в очередь TCP-сервера, пока не будет заполнен приемный буфер.

    В табл. 4.6 показано действительное число установленных в очередь соединений для различных значений аргумента backlog в операционных системах, показанных на рис. 1.7. Семь операционных систем помещены в пять колонок, что иллюстрирует многообразие значений аргумента backlog.

    Таблица 4.6. Действительное количество соединений в очереди для различных значений аргумента backlog

    backlog
    MacOS 10.2.6 AIX 5.1
    Linux 2.4.7
    HP-UX 11.11
    FreeBSD 4.8 FreeBSD 5.1
    Solaris 2.9

    0
    1
    3
    1
    1
    1

    1
    2
    4
    1
    2
    2

    2
    4
    5
    3
    3
    4

    3
    5
    6
    4
    4
    5

    4
    7
    7
    6
    5
    6

    5
    8
    8
    7
    6
    8

    6
    10
    9
    9
    7
    10

    7
    И
    10
    10
    8
    11

    8
    13
    11
    12
    9
    13

    9
    14
    12
    13
    10
    14

    10
    16
    13
    15
    11
    16

    11
    17
    14
    16
    12
    17

    12
    19
    15
    18
    13
    19

    13
    20
    16
    19
    14
    20

    14
    22
    17
    21
    15
    22

    Системы AIX, BSD/ОХ и SunOS реализуют традиционный алгоритм Беркли, хотя последний не допускает значения аргумента backlog больше пяти. В системах HP-UX и Solaris 2.6 используется другой поправочный множитель к аргументу backlog. Системы Digital Unix, Linux и UnixWare воспринимают этот аргумент буквально, то есть не используют поправочный множитель, а в Solaris 2.5.1 к аргументу backlog просто добавляется единица.

    ПРИМЕЧАНИЕ

    Программа для измерения этих значений представлена в решении упражнения 15.4.

    Как мы отмечали, традиционно аргумент backlog задавал максимальное значение для суммы обеих очередей. В 1996 году была предпринята новая атака через Интернет, названная SYN flooding (лавинная адресация сегмента SYN). Написанная хакером программа отправляет жертве сегменты SYN с высокой частотой, заполняя очередь не полностью установленных соединений для одного или нескольких портов TCP. (Хакером мы называем атакующего, как сказано в предисловии к [20].) Кроме того, IP-адрес отправителя каждого сегмента SYN задается случайным числом — формируются вымышленные IP-адреса (IP spoofing), что ведет к получению доступа обманным путем. Таким образом, сегмент сервера SYN/ACK уходит в никуда. Это не позволяет серверу узнать реальный IP-адрес хакера. Очередь не полностью установленных соединений заполняется ложными сегментами SYN, в результате чего для подлинных сегментов SYN в ней не хватает места — происходит отказ в обслуживании (denial of service) нормальных клиентов. Существует два типичных способа противостояния этим атакам [8]. Но самое интересное в этом примечании — это еще одно обращение к вопросу о том, что на самом деле означает аргумент backlog функции listen. Он должен задавать максимальное число установленных соединений для данного сокета, которые ядро помещает в очередь. Ограничение количества установленных соединений имеет целью приостановить получение ядром новых запросов на соединение для данного сокета, когда их не принимает приложение (по любой причине). Если система реализует именно такую интерпретацию, как, например, BSD/OS 3.0, то приложению не нужно задавать большие значения аргумента backlog только потому, что сервер обрабатывает множество клиентских запросов (например, занятый веб-сервер), или для защиты от «наводнения» SYN (лавинной адресации сегмента SYN). Ядро обрабатывает множество не полностью установленных соединений вне зависимости от того, являются ли они законными или приходят от хакера. Но даже в такой интерпретации мы видим (см. табл. 4.6), что значения 5 тут явно недостаточно.

    Данный текст является ознакомительным фрагментом.

    Читайте также

    Функция pthread_rwlock_rdlock

    Функция pthread_rwlock_rdlock
    Текст функции pthread_rwlock_rdlock приведен в листинге 8.4.Листинг 8.4. Функция pthread_rwlock_rdlock: получение блокировки на чтение//my_rwlock/pthread_rwlock_rdlock.с1  #include «unpipc.h»2  #include «pthread_rwlock.h»3  int4  pthread_rwlock_rdlock(pthread_rwlock_t *rw)5  {6   int result;7   if (rw-&gt;rw_magic != RW_MAGIC)8    return(EINVAL);9   if ((result =

    Функция pthread_rwlock_tryrdlock

    Функция pthread_rwlock_tryrdlock
    В листинге 8.5 показана наша реализация функции pthread_rwlock_tryrdlock, которая не вызывает приостановления вызвавшего ее потока.Листинг 8.5. Функция pthread_rwlock_tryrdlock: попытка заблокировать ресурс для чтения//my_rwlock/pthread_rwlock_tryrdlock.с1  #include «unpipc.h»2  #include

    Функция pthread_rwlock_wrlock

    Функция pthread_rwlock_wrlock
    Текст функции pthread_rwlock_wrlock приведен в листинге 8.6.11-17 Если ресурс заблокирован на считывание или запись (значение rw_refcount отлично от 0), мы приостанавливаем выполнение потока. Для этого мы увеличиваем rw_nwaitwriters и вызываем pthread_cond_wait с условной переменной

    Функция pthread_rwlock_unlock

    Функция pthread_rwlock_unlock
    Последняя функция, pthread_rwlock_unlock, приведена в листинге 8.8.Листинг 8.8. Функция pthread_rwlock_unlock: разблокирование ресурса//my_rwlock/pthread_rwlock_unlock.c1  #include «unpipc.h»2  #include «pthread_rwlock.h»3  int4  pthread_rwlock_unlock(pthread_rwlock_t *rw)5  {6   int result;7   if (rw-&gt;rw_magic != RW_MAGIC)8    return(EINVAL);9   if ((result =

    Функция sem_open

    Функция sem_open
    В листинге 10.22 приведен текст функции sem_open, которая создает новый семафор или открывает существующий.Листинг 10.22. Функция sem_open//my_pxsem_fifo/sem_open.с1  #include «unpipc.h»2  #include «semaphore.h»3  #include &lt;stdarg.h&gt; /* для произвольного списка аргументов */4  mysem_t *5  mysem_open(const char *pathname, int

    Функция SUM

    Функция SUM
    Ваши возможности в подведении итогов не ограничены простым подсчетом записей. Используя функцию SUM, можно генерировать итоговые результаты для всех возвращаемых записей по любым числовым полям. Например, для создания запроса, который генерирует итоги по

    Функция uni()

    Функция uni()
    Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book

    Функция uni()

    Функция uni()
    Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book

    Хэш-функция.

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

    Функция uni()

    Функция uni()
    Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book

    Хэш-функция

    Хэш-функция
    Однако описанная выше схема имеет ряд существенных недостатков. Она крайне медлительна и производит слишком большой объём данных — по меньшей мере вдвое больше объёма исходной информации. Улучшением такой схемы становится введение в процесс преобразования

    НАЗВАНИЕ
    listen — прослушивает соединения на сокете

    СИНТАКСИС
    #include

    int listen(int s, int backlog);

    ОПИСАНИЕ
    Для того, чтобы принимать соединения, сначала необходимо
    создать сокет с помощью функции socket(2), затем показать
    готовность принимать соединения и задать лимит входящих
    соединений с помощью listen, и только после этого
    принимать соединения с помощью accept(2). Системный вызов
    listen посылается только к сокетам типа SOCK_STREAM или
    SOCK_SEQPACKET.

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

    ЗАМЕЧАНИЯ
    Начиная с версии Linux 2.2, поведение параметра backlog на
    TCP-сокетах изменилось. Теперь вместо числа неоконченных
    запросов он определяет очередь полностью установленных
    сокетов, ожидающих, пока процесс примет их. Максимальная
    длина очереди сокетов, установленных не полностью, может
    быть задана параметром tcp_max_syn_backlog с помощью
    sysctl. Когда разрешено использование syncookies,
    логическая максимальная длина не указана и этот параметр,
    установленный sysctl, игнорируется. Для более подробной
    информации смотрите tcp(7).

    ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

    При успешном завершении вызова возвращаемое значение равно
    нулю. В случае ошибки возвращается -1, и переменной errno
    присваивается номер ошибки.

    КОДЫ ОШИБОК
    EADDRINUSE
    Другой сокет уже привязан к этому порту.

    EBADF Параметр s не является правильным описателем.

    ENOTSOCK
    Параметр s не является сокетом.

    EOPNOTSUPP
    Тип сокета не поддерживает операцию listen.

    СООТВЕТСТВИЕ СТАНДАРТАМ
    Single Unix, 4.4BSD, POSIX 1003.1g draft. Впервые
    системный вызов listen появился в 4.2BSD.

    НАЙДЕННЫЕ ОШИБКИ
    Если сокет имеет тип AF_INET, а аргумент backlog больше,
    чем константа SOMAXCONN (128 в Linux 2.0 и 2.2), то он
    «обрезается» до SOMAXCONN. Не полагайтесь на это значение
    при создании переносимых в другие системы приложений,
    потому что BSD (и некоторые её потомки) ограничивает
    размер очереди до 5.

    Читать новости Linux в Telegram ✆

    listen() — Unix, Linux System Call

    Tutorials Point

    Google

    Web

    This Site

      Unix for Beginners

      Unix Shell Programming

      Advanced Unix

      Unix Useful References

      Unix Useful Resources

      Selected Reading

    Copyright © 2014 by tutorialspoint

      Home     References     Discussion Forums     About TP  

    previous
    next

    AddThis Social Bookmark Button

    Advertisements


    NAME

    listen — listen for connections on a socket

    SYNOPSIS

    #include <sys/socket.h>

    int listen(int sockfd, int backlog);

    DESCRIPTION

    To accept connections, a socket is first created with
    socket(2),
    a willingness to accept incoming connections and a queue limit for incoming
    connections are specified with
    listen(), and then the connections are
    accepted with
    accept(2).
    The
    listen() call applies only to sockets of type
    SOCK_STREAM or
    SOCK_SEQPACKET.

    The
    backlog parameter defines the maximum length the queue of pending connections may
    grow to. If a connection request arrives with the queue full the client
    may receive an error with an indication of
    ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be
    ignored so that retries succeed.

    NOTES

    The behaviour of the
    backlog parameter on TCP sockets changed with Linux 2.2.
    Now it specifies the queue length for
    completely established sockets waiting to be accepted, instead of the number of incomplete
    connection requests. The maximum length of the queue for incomplete sockets
    can be set using the
    tcp_max_syn_backlog sysctl.
    When syncookies are enabled there is no logical maximum
    length and this sysctl setting is ignored.
    See
    tcp(7)
    for more information.

    RETURN VALUE

    On success, zero is returned. On error, -1 is returned, and
    errno is set appropriately.

    ERRORS

    Tag Description
    EADDRINUSE
      Another socket is already listening on the same port.
    EBADF The argument
    sockfd is not a valid descriptor.
    ENOTSOCK
      The argument
    sockfd is not a socket.
    EOPNOTSUPP
      The socket is not of a type that supports the
    listen() operation.

    CONFORMING TO

    4.4BSD, POSIX.1-2001.
    The
    listen() function call first appeared in 4.2BSD.

    BUGS

    If the socket is of type
    AF_INET, and the
    backlog argument is greater
    than the constant
    SOMAXCONN (128 in Linux 2.0 & 2.2), it is silently truncated
    to
    SOMAXCONN.

    SEE ALSO

    • accept (2)

    • bind (2)

    • connect (2)

    • socket (2)


    previous
    next

    Printer Friendly


    Advertisements

      

    Advertisements

    listen() — Unix, Linux System Call

    Tutorials Point

    Google

    Web

    This Site

      Unix for Beginners

      Unix Shell Programming

      Advanced Unix

      Unix Useful References

      Unix Useful Resources

      Selected Reading

    Copyright © 2014 by tutorialspoint

      Home     References     Discussion Forums     About TP  

    previous
    next

    AddThis Social Bookmark Button

    Advertisements


    NAME

    listen — listen for connections on a socket

    SYNOPSIS

    #include <sys/socket.h>

    int listen(int sockfd, int backlog);

    DESCRIPTION

    To accept connections, a socket is first created with
    socket(2),
    a willingness to accept incoming connections and a queue limit for incoming
    connections are specified with
    listen(), and then the connections are
    accepted with
    accept(2).
    The
    listen() call applies only to sockets of type
    SOCK_STREAM or
    SOCK_SEQPACKET.

    The
    backlog parameter defines the maximum length the queue of pending connections may
    grow to. If a connection request arrives with the queue full the client
    may receive an error with an indication of
    ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be
    ignored so that retries succeed.

    NOTES

    The behaviour of the
    backlog parameter on TCP sockets changed with Linux 2.2.
    Now it specifies the queue length for
    completely established sockets waiting to be accepted, instead of the number of incomplete
    connection requests. The maximum length of the queue for incomplete sockets
    can be set using the
    tcp_max_syn_backlog sysctl.
    When syncookies are enabled there is no logical maximum
    length and this sysctl setting is ignored.
    See
    tcp(7)
    for more information.

    RETURN VALUE

    On success, zero is returned. On error, -1 is returned, and
    errno is set appropriately.

    ERRORS

    Tag Description
    EADDRINUSE
      Another socket is already listening on the same port.
    EBADF The argument
    sockfd is not a valid descriptor.
    ENOTSOCK
      The argument
    sockfd is not a socket.
    EOPNOTSUPP
      The socket is not of a type that supports the
    listen() operation.

    CONFORMING TO

    4.4BSD, POSIX.1-2001.
    The
    listen() function call first appeared in 4.2BSD.

    BUGS

    If the socket is of type
    AF_INET, and the
    backlog argument is greater
    than the constant
    SOMAXCONN (128 in Linux 2.0 & 2.2), it is silently truncated
    to
    SOMAXCONN.

    SEE ALSO

    • accept (2)

    • bind (2)

    • connect (2)

    • socket (2)


    previous
    next

    Printer Friendly


    Advertisements

      

    Advertisements

    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии

    А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • При архивации ошибка при доступе к удаленной общей папке
  • При внутрибрюшном кровотечении ошибкой является