Функция WSAAccept (winsock2.h)

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

Синтаксис

SOCKET WSAAPI WSAAccept(
  [in]      SOCKET          s,
  [out]     sockaddr        *addr,
  [in, out] LPINT           addrlen,
  [in]      LPCONDITIONPROC lpfnCondition,
  [in]      DWORD_PTR       dwCallbackData
);

Параметры

[in] s

Дескриптор, идентифицирующий сокет, прослушивающий подключения после вызова функции прослушивания .

[out] addr

Необязательный указатель на структуру sockaddr , которая получает адрес подключающейся сущности, как известно на уровне связи. Точный формат параметра addr определяется семейством адресов, установленным при создании сокета.

[in, out] addrlen

Необязательный указатель на целое число, содержащее длину структуры sockaddr, на которую указывает параметр addr , в байтах.

[in] lpfnCondition

Адрес необязательной функции условия, указанной приложением, которая принимает или отклоняет решение на основе сведений о вызывающем объекте, передаваемых в качестве параметров, и при необходимости создает или присоединяет группу сокетов, присваивая соответствующее значение результирующим параметру g этой функции. Если этот параметр имеет значение NULL, то функция условия не вызывается.

[in] dwCallbackData

Данные обратного вызова, передаваемые в определяемую приложением функцию условия в качестве значения параметра dwCallbackData, передаваемого в функцию условия. Этот параметр применим, только если параметр lpfnCondition не имеет значения NULL. Этот параметр не интерпретируется сокетами Windows.

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

Если ошибка не возникает, WSAAccept возвращает значение типа SOCKET, которое является дескриптором для принятого сокета. В противном случае возвращается значение INVALID_SOCKET, а определенный код ошибки можно получить, вызвав WSAGetLastError.

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

Код ошибки Значение
WSAEACCES
Предпринята попытка получить доступ к сокету способом, запрещенным его разрешениями на доступ. Эта ошибка возвращается, если время ожидания запроса на подключение истекло или было отозвано.
WSAECONNREFUSED
Не удалось подключиться, так как целевой компьютер отказался от него. Эта ошибка возвращается, если запрос на подключение был принудительно отклонен, как указано в возвращаемом значении функции условия (CF_REJECT).
WSAECONNRESET
существующее соединение было принудительно завершено удаленным узлом. Эта ошибка возвращается при указании входящего подключения, но впоследствии была прервана удаленным одноранговым узелом перед принятием вызова.
WSAEFAULT
Система обнаружила недопустимый адрес указателя при попытке использовать аргумент указателя в вызове. Эта ошибка возвращается, если параметр addrlen слишком мал или addr или lpfnCondition не является частью адресного пространства пользователя.
WSAEINTR
Операция блокировки была прервана вызовом WSACancelBlockingCall. Эта ошибка возвращается, если блокирующий вызов Windows Sockets 1.1 был отменен через WSACancelBlockingCall.
WSAEINPROGRESS
В данный момент выполняется блокирующая операция. Эта ошибка возвращается, если выполняется блокирующий вызов Windows Sockets 1.1.
WSAEINVAL
Указан недопустимый аргумент. Эта ошибка возвращается, если прослушивание не было вызвано до WSAAccept, возвращаемое значение функции условия не является допустимым или в любом случае, когда указанный сокет находится в недопустимом состоянии.
WSAEMFILE
Слишком много открытых сокетов. Эта ошибка возвращается, если очередь не является непустой при входе в WSAAccept и нет доступных дескрипторов сокетов.
WSAENETDOWN
Операция на сокете обнаружила отключение сети. Эта ошибка возвращается в случае сбоя сетевой подсистемы.
WSAENOBUFS
Не удалось выполнить операцию с сокетом, так как в системе недостаточно места в буфере или из-за переполнения очереди. Эта ошибка возвращается, если буфер недоступен.
WSAENOTSOCK
Предпринята попытка выполнить операцию с тем, что не является сокетом. Эта ошибка возвращается, если дескриптор сокета, переданный в параметре s , не является сокетом.
WSAEOPNOTSUPP
Семейство протоколов не настроено в системе или для него не существует реализации. Эта ошибка возвращается, если указанный сокет не является типом, поддерживающим службу, ориентированную на подключение.
WSAEWOULDBLOCK
Неблокирующая операция сокета не может быть завершена немедленно. Эта ошибка возвращается, если сокет помечается как неблокирующий и нет подключений для принятия.
WSANOTINITIALISED
Либо приложение не вызывало WSAStartup, либо WSAStartup завершилось сбоем. Эта ошибка возвращается из-за успешного вызова функции WSAStartup dit не происходит до использования этой функции.
WSATRY_AGAIN
Обычно это временная ошибка при разрешении имени узла, и она означает, что локальный сервер не получил ответа от заслуживающего доверия сервера. Эта ошибка возвращается, если принятие запроса на подключение было отложено, как указано в возвращаемом значении функции условия (CF_DEFER).

Комментарии

Функция WSAAccept извлекает первое подключение в очереди ожидающих подключений в сокетах и проверяет его на соответствие функции условия при условии, что указана функция условия (т. е. не NULL). Если функция condition возвращает CF_ACCEPT, WSAAccept создает новый сокет. Вновь созданный сокет имеет те же свойства, что и сокеты, включая асинхронные события, зарегистрированные с помощью WSAsyncSelect или WSAEventSelect. Если функция condition возвращает CF_REJECT, WSAAccept отклоняет запрос на подключение. Функция condition выполняется в том же потоке, что и эта функция, и должна вернуться как можно скорее. Если решение не может быть принято немедленно, функция условия должна возвращать CF_DEFER, чтобы указать, что решение не было принято, и поставщик услуг не должен предпринимать никаких действий по этому запросу на подключение. Когда приложение будет готово к выполнению действия с запросом на подключение, оно снова вызовет WSAAccept и вернет CF_ACCEPT или CF_REJECT в качестве значения, возвращаемого функцией условия.

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

Сокет в неблокированном режиме (блокировка) завершается сбоем с ошибкой WSAEWOULDBLOCK , когда приложение вызывает WSAAccept и в очереди нет ожидающих подключений. После успешного выполнения WSAAccept и возврата нового дескриптора сокета принятый сокет нельзя использовать для приема дополнительных подключений. Исходный сокет остается открытым и прослушивает новые запросы на подключение.

Параметр addr — это результирующий параметр, который заполняется адресом подключающейся сущности, как известно уровню связи. Точный формат параметра addr определяется семейством адресов, в котором происходит обмен данными. Addrlen является параметром значения и результата; Изначально он должен содержать объем пространства, на который указывает addr. При возврате он будет содержать фактическую длину (в байтах) возвращенного адреса. Этот вызов используется с типами сокетов, ориентированными на подключение, такими как SOCK_STREAM. Если аргумент addr и (или ) addrlen равен NULL, то сведения об удаленном адресе принятого сокета не возвращаются. В противном случае эти два параметра будут заполнены, если подключение будет успешно принято.

Прототип функции условия определен в файле заголовка Winsock2.h как LPCONDITIONPROC, как показано ниже.

int CALLBACK 
ConditionFunc( 
  IN     LPWSABUF    lpCallerId, 
  IN     LPWSABUF    lpCallerData, 
  IN OUT LPQOS       lpSQOS, 
  IN OUT LPQOS       lpGQOS,
  IN     LPWSABUF    lpCalleeId, 
  IN     LPWSABUF    lpCalleeData, 
  OUT    GROUP FAR * g, 	
  IN     DWORD_PTR   dwCallbackData
);

ConditionFunc — это заполнитель для функции обратного вызова, указанной приложением. Фактическая функция условия должна находиться в библиотеке DLL или модуле приложения. Он экспортируется в файл определения модуля.

Параметр lpCallerId указывает на структуру WSABUF, содержащую адрес подключающейся сущности, где его параметр len — это длина буфера в байтах, а параметр buf — указатель на буфер. lpCallerData — это параметр значения, содержащий любые пользовательские данные. Сведения в этих параметрах отправляются вместе с запросом на подключение. Если идентификация вызывающего объекта или данные вызывающей стороны недоступны, соответствующие параметры будут иметь значение NULL. Многие сетевые протоколы не поддерживают данные вызывающего абонента во время подключения. Ожидается, что большинство обычных сетевых протоколов будут поддерживать сведения об идентификаторе вызывающего абонента во время запроса подключения. Часть Buf WSABUF , на которую указывает lpCallerId , указывает на sockaddr. Структура sockaddr интерпретируется в соответствии с семейством адресов (обычно путем приведения sockaddr к определенному типу, относямуся к семейству адресов).

Параметр lpSQOS ссылается на структуры FLOWSPEC для сокетов, заданных вызывающим объектом, по одному для каждого направления, за которым следуют все дополнительные параметры, зависящие от поставщика. Значения спецификации потока отправки или получения будут игнорироваться для любых однонаправленных сокетов. Значение NULL указывает, что качество обслуживания, предоставляемое вызывающим абонентом, отсутствует и что согласование невозможно. Указатель lpSQOS, отличный от NULL, указывает, что требуется согласование качества обслуживания или что поставщик готов принять качество запроса на обслуживание без согласования.

Параметр lpGQOS зарезервирован и должен иметь значение NULL. (зарезервировано для будущего использования с группами сокетов) ссылается на структуру FLOWSPEC для группы сокетов, которую нужно создать вызывающей стороне, по одному для каждого направления, за которой следуют любые дополнительные параметры, относящиеся к поставщику. Значение NULL для lpGQOS указывает на отсутствие качества обслуживания группы, указанной вызывающим объектом. Если необходимо выполнить согласование, можно вернуть сведения о качестве обслуживания.

lpCalleeId — это параметр, содержащий локальный адрес подключенной сущности. Часть buf WSABUF, на которую указывает lpCalleeId , указывает на структуру sockaddr . Структура sockaddr интерпретируется в соответствии с семейством адресов (как правило, путем приведения sockaddr к определенному типу, относямуся к семейству адресов, например структура sockaddr_in).

lpCalleeData — это результирующий параметр, используемый функцией условия для передачи пользовательских данных в подключающуюся сущность. lpCalleeData-len> изначально содержит длину буфера, выделенного поставщиком услуг и на который указывает lpCalleeData-buf>. Нулевое значение означает, что передача пользовательских данных обратно вызывающей стороне не поддерживается. Функция condition должна скопировать данные в lpCalleeData-len> в байты данных в lpCalleeData-buf>, а затем обновить lpCalleeData-len>, чтобы указать фактическое количество переданных байтов. Если данные пользователя не передаются обратно вызывающей стороне, функция condition должна задать для lpCalleeData-len> значение 0. Формат всех данных адреса и пользователя зависит от семейства адресов, к которому принадлежит сокет.

Параметр g назначается в функции condition для указания любого из следующих действий:

  • Если g — это существующий идентификатор группы сокетов, добавьте в эту группу s при условии выполнения всех требований, установленных этой группой.
  • Если g = SG_UNCONSTRAINED_GROUP, создайте группу неограниченного сокета и укажите в качестве первого члена.
  • Если g = SG_CONSTRAINED_GROUP, создайте ограниченную группу сокетов и укажите в качестве первого члена.
  • Если g = ноль, операция группы не выполняется.
Для групп без ограничений любой набор сокетов можно сгруппировать, если они поддерживаются одним поставщиком услуг. Ограниченная группа сокетов может состоять только из сокетов, ориентированных на подключение, и требует, чтобы подключения во всех сгруппированных сокетах были к одному адресу на одном узле. Для вновь созданных групп сокетов идентификатор новой группы можно получить с помощью функции getsockopt с параметром уровняSOL_SOCKET и параметром optname , равным SO_GROUP_ID. Группа сокетов и ее идентификатор группы сокетов остаются действительными до закрытия последнего сокета, принадлежащего этой группе сокетов. Идентификаторы групп сокетов уникальны во всех процессах для данного поставщика услуг. Группа сокетов и связанный с ней идентификатор остаются действительными до закрытия последнего сокета, принадлежащего этой группе сокетов. Идентификаторы групп сокетов уникальны во всех процессах для конкретного поставщика услуг. Дополнительные сведения о группах сокетов см. в примечаниях к функциям WSASocket .

Значение параметра dwCallbackData , передаваемое функции condition, — это значение, переданное в качестве параметра dwCallbackData в исходном вызове WSAAccept . Это значение интерпретируется только клиентом сокета Windows версии 2. Это позволяет клиенту передавать некоторые сведения о контексте с сайта вызова WSAAccept через функцию condition. Это также предоставляет функцию условия с любыми дополнительными сведениями, необходимыми для определения того, следует ли принимать соединение. Типичным способом использования является передача указателя (подходящего приведения) в структуру данных, содержащую ссылки на определяемые приложением объекты, с которыми связан этот сокет.

Примечание Чтобы защитить использование функции WSAAccept от атак SYN, приложения должны выполнить полное подтверждение TCP (SYN-SYNACK-ACK) перед отправкой сообщения о запросе на подключение. Защита от атак SYN таким образом приводит к тому, что параметр сокета SO_CONDITIONAL_ACCEPT становится неработоспособным; Условная функция по-прежнему вызывается, и функция WSAAccept работает правильно, но серверные приложения, использующие клиенты, не могут выполнить подтверждение, будут работать неправильно.
 
Примечание При выполнении блокирующего вызова Winsock, например WSAAccept, Winsock может потребоваться дождаться сетевого события, прежде чем вызов сможет завершиться. В этой ситуации Winsock выполняет оповещенное ожидание, которое может быть прервано асинхронным вызовом процедуры (APC), запланированным в том же потоке. Выполнение другого блокирующего вызова Winsock внутри APC, который прервал текущий блокирующий вызов Winsock в том же потоке, приведет к неопределенному поведению, и клиенты Winsock никогда не должны пытаться его выполнять.
 

Пример кода

В следующем примере показано использование функции WSAAccept .
#include <winsock2.h>
#include <stdio.h>
#include <windows.h>

/* Define an example conditional function that depends on the pQos field */
int CALLBACK ConditionAcceptFunc(
    LPWSABUF lpCallerId,
    LPWSABUF lpCallerData,
    LPQOS pQos,
    LPQOS lpGQOS,
    LPWSABUF lpCalleeId,
    LPWSABUF lpCalleeData,
    GROUP FAR * g,
    DWORD_PTR dwCallbackData
    )
{

    if (pQos != NULL) {
        RtlZeroMemory(pQos, sizeof(QOS));
        return CF_ACCEPT;
    } else
        return CF_REJECT;
}

int main() {

    /* Declare and initialize variables */
    WSADATA wsaData;
    SOCKET ListenSocket, AcceptSocket;
    struct sockaddr_in saClient;
    int iClientSize = sizeof(saClient);
    u_short port = 27015;
    char* ip;
    sockaddr_in service;
    int error;

    /* Initialize Winsock */
    error = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (error) {
        printf("WSAStartup() failed with error: %d\n", error);
        return 1;
    }

    /* Create a TCP listening socket */
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {  
        printf("socket() failed with error: %d\n", WSAGetLastError() );
        WSACleanup();
        return 1;
    }

    /*-----------------------------------------  
     *  Set up the sock addr structure that the listening socket
     *  will be bound to. In this case, the structure holds the
     * local IP address and the port specified. */
    service.sin_family = AF_INET;
    service.sin_port = htons(port);
    hostent* thisHost;
    thisHost = gethostbyname("");
    ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);
    service.sin_addr.s_addr = inet_addr(ip);

    /*-----------------------------------------
     *  Bind the listening socket to the IP address.
     * and port number specified by the sockaddr structure. */
    error = bind(ListenSocket, (SOCKADDR *) &service, sizeof(SOCKADDR));
    if (error == SOCKET_ERROR) {  
        printf("bind() failed with error: %d\n", WSAGetLastError() );
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
  
    /* Make the socket listen for incoming connection requests */
    error = listen(ListenSocket, 1);
    if (error == SOCKET_ERROR) {  
        printf("listen() failed with error: %d\n", WSAGetLastError() );
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    printf("Listening...\n");
  
    /*-----------------------------------------
     *  Accept an incoming connection request on the
     *  listening socket and transfer control to the 
     * accepting socket. */
    AcceptSocket = WSAAccept(ListenSocket, (SOCKADDR*) &saClient, &iClientSize, 
        &ConditionAcceptFunc, NULL);
 
    /*  Now do some work with the AcceptSocket 
     *  At this point, the application could
     *  handle data transfer on the socket, or other socket
     * functionality.*/
    
    /* Then clean up and quit */

    closesocket(AcceptSocket);
    closesocket(ListenSocket);
    WSACleanup();

    return 0;
}

Windows Phone 8. Эта функция поддерживается для приложений Магазина Windows Phone на Windows Phone 8 и более поздних версиях.

Windows 8.1 и Windows Server 2012 R2. Эта функция поддерживается для приложений Магазина Windows на Windows 8.1, Windows Server 2012 R2 и более поздних версиях.

Требования

Требование Значение
Минимальная версия клиента Windows 8.1, Windows Vista [классические приложения | Приложения UWP]
Минимальная версия сервера Windows Server 2003 [классические приложения | Приложения UWP]
Целевая платформа Windows
Header winsock2.h
Библиотека Ws2_32.lib
DLL Ws2_32.dll

См. также раздел

WSAsyncSelect

WSAConnect

WSASocket

Функции Winsock

Справочник по Winsock

Принять

bind

connect;

getsockopt

listen

select

sockaddr

Сокета