Как Winsock2 listen() блокирует?

MSDN говорит, что : Listen() — это блокирующий вызов. Фрагмент кода функции, в которой я использовал listen(), показан ниже:

sockaddr_in addr    = {0};
int     addrlen = sizeof(addr);
SOCKET  sock_listen;

if(-1 == (sock_listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
    cout<<"error";
}   

addr.sin_family = AF_INET;
/* Network byte ordered address for loopback */
addr.sin_addr.s_addr= inet_addr("127.0.0.1");
/* Let service provider assign a unique port from dynamic client port range */  
addr.sin_port   = 0;                        

if(-1 == bind(sock_listen, (const sockaddr *)&addr, addrlen))       
{
    CloseHandle((HANDLE)sock_listen_fd);
    cout<<"error";
}

if(-1 == getsockname(sock_listen, (sockaddr *)&addr, &addrlen))
{     
    CloseHandle((HANDLE)sock_listen);
    cout<<"error";
}

u_long mode = 0;
if(SOCKET_ERROR == ioctlsocket(sock_listen, FIONBIO, &mode))
{
    cout<<"ioctl failed";
}

if(SOCKET_ERROR == listen(sock_listen, 1))
{
    cout<<"listen error";
}
cout<<"Passed listen";
if(SOCKET_ERROR == (s = ACL_accept(sock_listen_fd, NULL, NULL)))
{
       cout<<"accept error";
}

По умолчанию дескриптор сокета создается как тип блокировки. Чтобы дополнительно убедиться, что он вызвал ioctlsocket(), чтобы сделать тип блокировки дескриптора сокета.

Вывод: Пройдено прослушивание

Таким образом, поток не блокируется при прослушивании (), вместо этого он блокируется при принятии, что, насколько мне известно, является правильным способом. Также на странице Linux MAN ясно объясняется:

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

Тогда почему MSDN говорит, что прослушивание является блокирующим вызовом Winsock. Имеют ли они в виду просто какое-то внутреннее ожидание какого-то события?


person Aravind    schedule 20.05.2013    source источник
comment
Я заметил, что цитата из документации, которую вы скопировали, относится к Listen, а не listen. Возможно, это две разные функции?   -  person Celada    schedule 21.05.2013
comment
@Celada: Нет. Оба одинаковы   -  person Aravind    schedule 21.05.2013


Ответы (3)


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

Сокеты Windows позволяют устанавливать сторонних поставщиков для поддержки дополнительных протоколов или существующих протоколов с дополнительными функциями. Поскольку SPI Winsock не запрещает сторонним поставщикам блокировать listen, приложения должны следовать рекомендациям MSDN в отношении APC и вложенных вызовов Winsock.

Кажется вероятным, что встроенный провайдер TCP/IP никогда не блокирует listen, но, насколько я знаю, нет явной гарантии этого.

person Harry Johnston    schedule 22.05.2013
comment
Да, это может быть причиной того, что MSDN разместила этот абзац там. Спасибо вам всем. - person Aravind; 22.05.2013

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

Редактировать 0:

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

person Nikolai Fetissov    schedule 21.05.2013
comment
Удерживает этот замок для какой противоречивой цели? Я бы назвал это «атомарным» вызовом, а не «блокирующим» вызовом. - person user207421; 21.05.2013
comment
Да, возможно, ты прав. Это уж точно не блокирует ни на одной вменяемой ОС. Но тогда Windows далека от здравого смысла. Но формулировку изменю, спасибо. - person Nikolai Fetissov; 21.05.2013

Если MSDN говорит об этом, это ошибка. Это не блокирующий вызов. Блокировать нечего, уж точно не «внешнее сетевое событие».

Абзац, в котором говорится об этом, явно является шаблонным, скопированным в слишком много мест.

person user207421    schedule 21.05.2013
comment
Я не знаю ... SPI Windows Sockets, похоже, не запрещает сторонним поставщикам протоколов блокировать listen. - person Harry Johnston; 22.05.2013
comment
Так что все, что нам нужно сейчас, это хотя бы одно правдоподобное предположение относительно того, что именно они могут заблокировать + на +. Я не согласен с вашим предложением о драйвере сетевой карты. listen() пока не имеет ничего общего с сетью. - person user207421; 22.05.2013
comment
Я могу привести один лишь слегка надуманный пример: если сетевой провайдер прозрачно перенаправляет сокет на удаленную систему, ему может потребоваться дождаться ответа этой удаленной системы. Я не знаю ни одного существующего программного обеспечения, которое делает подобные вещи, но оно может быть полезным; это позволит нескольким компьютерам совместно использовать один IP-адрес без ограничений NAT. - person Harry Johnston; 22.05.2013
comment
Кроме того, хотя обычному сетевому адаптеру не нужно сообщать о вызове listen, не может ли аппаратная разгрузка изменить это? - person Harry Johnston; 22.05.2013