Función WSAAccept (winsock2.h)

La función WSAAccept acepta condicionalmente una conexión basada en el valor devuelto de una función de condición, proporciona especificaciones de flujo de servicio de calidad y permite la transferencia de datos de conexión.

Sintaxis

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

Parámetros

[in] s

Descriptor que identifica un socket que escucha las conexiones después de una llamada a la función de escucha .

[out] addr

Puntero opcional a una estructura de sockaddr que recibe la dirección de la entidad de conexión, como se conoce en la capa de comunicaciones. El formato exacto del parámetro addr viene determinado por la familia de direcciones establecida cuando se creó el socket.

[in, out] addrlen

Puntero opcional a un entero que contiene la longitud de la estructura sockaddr a la que apunta el parámetro addr , en bytes.

[in] lpfnCondition

Dirección de una función de condición opcional especificada por la aplicación que realizará una decisión de aceptación o rechazo en función de la información del autor de la llamada que se pasa como parámetros y, opcionalmente, cree o una un grupo de sockets asignando un valor adecuado al parámetro de resultado g de esta función. Si este parámetro es NULL, no se llama a ninguna función de condición.

[in] dwCallbackData

Los datos de devolución de llamada pasados a la función de condición especificada por la aplicación como valor del parámetro dwCallbackData pasado a la función de condición. Este parámetro solo es aplicable si el parámetro lpfnCondition no es NULL. Windows Sockets no interpreta este parámetro.

Valor devuelto

Si no se produce ningún error, WSAAccept devuelve un valor de tipo SOCKET que es un descriptor para el socket aceptado. De lo contrario, se devuelve un valor de INVALID_SOCKET y se puede recuperar un código de error específico llamando a WSAGetLastError.

El entero al que hace referencia addrlen inicialmente contiene la cantidad de espacio al que apunta el agregador. Al devolver, contendrá la longitud real en bytes de la dirección devuelta.

Código de error Significado
WSAEACCES
Se ha intentado obtener acceso a un socket de una manera no permitida por los permisos de acceso. Este error se devuelve si la solicitud de conexión que se ofreció ha agotado el tiempo de espera o se ha retirado.
WSAECONNREFUSED
No se ha establecido ninguna conexión porque el equipo de destino la ha rechazado. Este error se devuelve si la solicitud de conexión se rechazó forzosamente como se indica en el valor devuelto de la función de condición (CF_REJECT).
WSAECONNRESET
El host remoto forzó el cierre de la conexión existente. Este error se devuelve de una conexión entrante indicada, pero posteriormente lo terminó el elemento del mismo nivel remoto antes de aceptar la llamada.
WSAEFAULT
El sistema ha detectado una dirección de puntero no válida al intentar usar un argumento de puntero en una llamada. Este error se devuelve del parámetro addrlen es demasiado pequeño o el addr o lpfnCondition no forma parte del espacio de direcciones del usuario.
WSAEINTR
Una operación de bloqueo se interrumpió mediante una llamada a WSACancelBlockingCall. Este error se devuelve si se canceló una llamada de Bloqueo de Windows Sockets 1.1 a través de WSACancelBlockingCall.
WSAEINPROGRESS
Se está ejecutando una operación de bloqueo actualmente. Este error se devuelve si una llamada a Windows Sockets 1.1 está en curso.
WSAEINVAL
Se ha proporcionado un argumento no válido. Este error se devuelve si la escucha no se invocó antes de WSAAccept, el valor devuelto de la función de condición no es válido o cualquier caso en el que el socket especificado esté en un estado no válido.
WSAEMFILE
Hay demasiados sockets abiertos. Este error se devuelve si la cola no está vacía tras la entrada a WSAAccept y no hay ningún descriptor de socket disponible.
WSAENETDOWN
Una operación de socket encontró una red inactiva. Este error se devuelve si se ha producido un error en el subsistema de red.
WSAENOBUFS
No se ha podido realizar una operación en un socket porque el sistema no tenía suficiente espacio en búfer o porque una cola estaba llena. Este error se devuelve si no hay ningún espacio en búfer disponible.
WSAENOTSOCK
Se ha intentado realizar una operación en algo que no es un socket. Este error se devuelve si el descriptor de socket pasado en el parámetro s no es un socket.
WSAEOPNOTSUPP
La familia de protocolos no se ha configurado en el sistema o no existe ninguna implementación para ella. Este error se devuelve si el socket al que se hace referencia no es un tipo que admite el servicio orientado a la conexión.
WSAEWOULDBLOCK
No se ha podido completar inmediatamente una operación de socket sin bloqueo. Este error se devuelve si el socket está marcado como no desbloqueado y no hay ninguna conexión que se acepte.
WSANOTINITIALISED
La aplicación no ha llamado a WSAStartup o WSAStartup no se pudo realizar. Este error se devuelve de una llamada correcta a la función WSAStartup que no se produce antes de usar esta función.
WSATRY_AGAIN
Éste es normalmente un error temporal durante la resolución de nombres de host y significa que el servidor local no recibió una respuesta de un servidor autorizado. Este error se devuelve si la aceptación de la solicitud de conexión se aplaza como se indica en el valor devuelto de la función de condición (CF_DEFER).

Comentarios

La función WSAAccept extrae la primera conexión en la cola de conexiones pendientes en los sockets y la comprueba con la función condition, siempre que se especifique la función condition (es decir, no NULL). Si la función condition devuelve CF_ACCEPT, WSAAccept crea un nuevo socket. El socket recién creado tiene las mismas propiedades que los sockets , incluidos los eventos asincrónicos registrados con WSAAsyncSelect o con WSAEventSelect. Si la función condition devuelve CF_REJECT, WSAAccept rechaza la solicitud de conexión. La función condition se ejecuta en el mismo subproceso que esta función y debe devolver lo antes posible. Si la decisión no se puede tomar inmediatamente, la función de condición debe devolver CF_DEFER para indicar que no se ha tomado ninguna decisión y que el proveedor de servicios debe tomar ninguna acción sobre esta solicitud de conexión. Cuando la aplicación esté lista para realizar acciones en la solicitud de conexión, invocará WSAAccept de nuevo y devolverá CF_ACCEPT o CF_REJECT como un valor devuelto de la función de condición.

Un socket en modo predeterminado (bloqueo) se bloqueará hasta que una conexión esté presente cuando una aplicación llama a WSAAccept y no hay ninguna conexión pendiente en la cola.

Se produce un error en un socket en modo de no bloqueo (bloqueo) con el error WSAEWOULDBLOCK cuando una aplicación llama a WSAAccept y no hay ninguna conexión pendiente en la cola. Una vez que WSAAccept se realiza correctamente y devuelve un nuevo identificador de socket, el socket aceptado no se puede usar para aceptar más conexiones. El socket original permanece abierto y escucha las nuevas solicitudes de conexión.

El parámetro addr es un parámetro de resultado que se rellena con la dirección de la entidad de conexión, como se conoce en la capa de comunicaciones. El formato exacto del parámetro addr viene determinado por la familia de direcciones en la que se está produciendo la comunicación. El addrlen es un parámetro value-result; debe contener inicialmente la cantidad de espacio al que apunta el agregador. Al devolver, contendrá la longitud real (en bytes) de la dirección devuelta. Esta llamada se usa con tipos de socket orientados a la conexión, como SOCK_STREAM. Si addr o addrlen son iguales a NULL, no se devuelve información sobre la dirección remota del socket aceptado. De lo contrario, estos dos parámetros se rellenarán si la conexión se acepta correctamente.

Un prototipo de la función de condición se define en el Winsock2.h archivo de encabezado como LPCONDITIONPROC, como se indica a continuación.

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 es un marcador de posición para la función de devolución de llamada especificada por la aplicación. La función de condición real debe residir en un módulo DLL o de aplicación. Se exporta en el archivo de definición de módulo.

El parámetro lpCallerId apunta a una estructura WSABUF que contiene la dirección de la entidad de conexión, donde su parámetro len es la longitud del búfer en bytes y su parámetro buf es un puntero al búfer. LpCallerData es un parámetro de valor que contiene los datos de usuario. La información de estos parámetros se envía junto con la solicitud de conexión. Si no hay datos de identificación o autor de llamada disponibles, los parámetros correspondientes serán NULL. Muchos protocolos de red no admiten datos del autor de llamada en tiempo de conexión. Se espera que la mayoría de los protocolos de red convencionales admitan la información del identificador del autor de la llamada en el momento de la solicitud de conexión. La parte buf del WSABUF a la que apunta lpCallerId apunta a un sockaddr. La estructura sockaddr se interpreta según su familia de direcciones (normalmente mediante la conversión del sockaddr a algún tipo específico de la familia de direcciones).

El parámetro lpSQOS hace referencia a las estructuras FLOWSPEC para los sockets especificados por el autor de la llamada, uno para cada dirección, seguido de cualquier parámetro adicional específico del proveedor. Los valores de especificación de flujo de envío o recepción se omitirán según corresponda para los sockets unidireccionales. Un valor NULL indica que no hay ninguna calidad de servicio proporcionada por el autor de la llamada y que no es posible ninguna negociación. Un puntero lpSQOS no NULL indica que se debe producir una negociación de calidad de servicio o que el proveedor está preparado para aceptar la calidad de la solicitud de servicio sin negociación.

El parámetro lpGQOS está reservado y debe ser NULL. (reservado para uso futuro con grupos de sockets) hace referencia a la estructura FLOWSPEC del grupo de sockets que el autor de la llamada va a crear, una para cada dirección, seguida de cualquier parámetro adicional específico del proveedor. Un valor NULL para lpGQOS indica que no hay calidad de servicio especificada por el autor de la llamada. La información de calidad del servicio se puede devolver si se va a realizar la negociación.

LpCalleeId es un parámetro que contiene la dirección local de la entidad conectada. La parte buf del WSABUF apuntada por lpCalleeId apunta a una estructura de sockaddr . La estructura sockaddr se interpreta según su familia de direcciones (normalmente mediante la conversión del sockaddr a algún tipo específico de la familia de direcciones, como struct sockaddr_in).

LpCalleeData es un parámetro de resultado utilizado por la función condition para devolver datos de usuario a la entidad de conexión. LpCalleeData-len> contiene inicialmente la longitud del búfer asignado por el proveedor de servicios y señalado por lpCalleeData-buf>. Un valor de cero significa que no se admite el paso de datos de usuario al autor de la llamada. La función condition debe copiar hasta lpCalleeData-len> bytes de datos en lpCalleeData-buf> y, a continuación, actualizar lpCalleeData-len> para indicar el número real de bytes transferidos. Si no se devuelven datos de usuario al autor de la llamada, la función condition debe establecer lpCalleeData-len> en cero. El formato de todos los datos de dirección y usuario es específico de la familia de direcciones a la que pertenece el socket.

El parámetro g se asigna dentro de la función condition para indicar cualquiera de las siguientes acciones:

  • Si g es un identificador de grupo de sockets existente, agregue s a este grupo, siempre que se cumplan todos los requisitos establecidos por este grupo.
  • Si g = SG_UNCONSTRAINED_GROUP, cree un grupo de sockets sin restricciones y tenga s como primer miembro.
  • Si g = SG_CONSTRAINED_GROUP, cree un grupo de sockets restringido y tenga s como primer miembro.
  • Si g = cero, no se realiza ninguna operación de grupo.
En el caso de los grupos sin restricciones, cualquier conjunto de sockets se puede agrupar siempre que sea compatible con un único proveedor de servicios. Un grupo de sockets restringidos solo puede constar de sockets orientados a la conexión y requiere que las conexiones de todos los sockets agrupados estén en la misma dirección del mismo host. En el caso de los grupos de sockets recién creados, el nuevo identificador de grupo se puede recuperar mediante la función getsockopt con el parámetro level establecido en SOL_SOCKET y el parámetro optname establecido en SO_GROUP_ID. Un grupo de sockets y su identificador de grupo de sockets asociado permanecen válidos hasta que se cierre el último socket que pertenezca a este grupo de sockets. Los identificadores de grupo de sockets son únicos en todos los procesos de un proveedor de servicios determinado. Un grupo de sockets y su identificador asociado permanecen válidos hasta que se cierre el último socket que pertenece a este grupo de sockets. Los identificadores de grupo de sockets son únicos en todos los procesos de un proveedor de servicios determinado. Para obtener más información sobre los grupos de sockets, vea los comentarios de las funciones WSASocket .

El valor del parámetro dwCallbackData pasado a la función condition es el valor pasado como parámetro dwCallbackData en la llamada WSAAccept original. Este valor solo lo interpreta el cliente de Windows Socket versión 2. Esto permite que un cliente pase información de contexto del sitio de llamada de WSAAccept a través de a la función condition. Esto también proporciona la función condition con cualquier información adicional necesaria para determinar si se debe aceptar la conexión o no. Un uso típico es pasar un puntero (conversión adecuada) a una estructura de datos que contiene referencias a objetos definidos por la aplicación con los que está asociado este socket.

Nota Para proteger el uso de la función WSAAccept frente a ataques SYN, las aplicaciones deben realizar protocolos de enlace TCP completos (SYN-SYNACK-ACK) antes de notificar la solicitud de conexión. La protección contra los ataques SYN de esta manera hace que la opción de socket SO_CONDITIONAL_ACCEPT sea inoperativa; Se sigue llamando a la función condicional y la función WSAAccept funciona correctamente, pero las aplicaciones de servidor que dependen de que los clientes no puedan realizar el protocolo de enlace no funcionarán correctamente.
 
Nota Al emitir una llamada de Winsock de bloqueo como WSAAccept, Winsock puede necesitar esperar un evento de red antes de que se pueda completar la llamada. Winsock realiza una espera alertable en esta situación, que se puede interrumpir mediante una llamada de procedimiento asincrónica (APC) programada en el mismo subproceso. La emisión de otra llamada winsock de bloqueo dentro de un APC que interrumpió una llamada de Winsock de bloqueo en curso en el mismo subproceso provocará un comportamiento indefinido y los clientes winsock nunca deben intentarlo.
 

Código de ejemplo

En el ejemplo siguiente se muestra el uso de la función 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: esta función es compatible con las aplicaciones de Windows Phone Store en Windows Phone 8 y versiones posteriores.

Windows 8.1 y Windows Server 2012 R2: esta función es compatible con las aplicaciones de la Tienda Windows en Windows 8.1, Windows Server 2012 R2 y versiones posteriores.

Requisitos

Requisito Value
Cliente mínimo compatible Windows 8.1, Windows Vista [aplicaciones de escritorio | Aplicaciones para UWP]
Servidor mínimo compatible Windows Server 2003 [aplicaciones de escritorio | aplicaciones para UWP]
Plataforma de destino Windows
Encabezado winsock2.h
Library Ws2_32.lib
Archivo DLL Ws2_32.dll

Consulte también

WSAAsyncSelect

WSAConnect

WSASocket

Funciones winsock

Referencia de Winsock

accept

bind

connect

getsockopt

listen

select

sockaddr

socket