Rutinas de bloqueo de Windows Sockets 1.1 y EINPROGRESS

Un problema importante en la portabilidad de aplicaciones desde un entorno de Sockets de Berkeley a un entorno de Windows implica el bloqueo; es decir, invocar una función que no devuelve hasta que se completa la operación asociada. Se produce un problema cuando la operación tarda un tiempo arbitrario en completarse: un ejemplo es una función recv , que podría bloquearse hasta que se hayan recibido datos del sistema del mismo nivel. El comportamiento predeterminado dentro del modelo Berkeley Sockets es para que un socket funcione en modo de bloqueo a menos que el programador solicite explícitamente que las operaciones se traten como no desbloqueadas. Los entornos de Windows Sockets 1.1 no podían asumir la programación preferente. Por lo tanto, se recomienda encarecidamente que los programadores usen las operaciones sin bloqueo (asincrónicas) si es posible con Windows Sockets 1.1. Dado que esto no siempre era posible, se proporcionaron las instalaciones de pseudo-bloqueo descritas en lo siguiente.

Nota

Windows Sockets 2 solo se ejecuta en sistemas operativos de 32 bits preferentes en los que los interbloqueos no son un problema. Los procedimientos de programación recomendados para Windows Sockets 1.1 no son necesarios en Windows Sockets 2.

 

Incluso en un socket de bloqueo, algunas funciones ( bind, getsockopt y getpeername por ejemplo) se completan inmediatamente. No hay ninguna diferencia entre un bloqueo y una operación de bloqueo para esas funciones. Otras operaciones, como recv, pueden completarse inmediatamente o tardar un tiempo arbitrario en completarse, en función de diversas condiciones de transporte. Cuando se aplica a un socket de bloqueo, estas operaciones se conocen como operaciones de bloqueo. Las siguientes funciones pueden bloquear:

Con Windows Sockets 1.1 de 16 bits, una operación de bloqueo que no se puede completar inmediatamente se controla mediante pseudoobjeción como se indica a continuación.

El proveedor de servicios inicia la operación, después escribe un bucle en el que envía los mensajes de Windows (que producen el procesador a otro subproceso, si es necesario) y, a continuación, comprueba la finalización de la función Windows Sockets. Si la función se ha completado o si se ha invocado WSACancelBlockingCall , la función de bloqueo se completa con un resultado adecuado.

Un proveedor de servicios debe permitir la instalación de una función de enlace de bloqueo que no procesa mensajes para evitar la posibilidad de volver a entrar mensajes mientras una operación de bloqueo está pendiente. La función de enlace de bloqueo más sencilla devolvería FALSE. Si un archivo DLL de Windows Sockets depende de los mensajes para la operación interna, puede ejecutar PeekMessage(hMyWnd...) antes de ejecutar el enlace de bloqueo de la aplicación para que pueda obtener sus mensajes sin afectar al resto del sistema.

En un entorno de Windows Sockets 1.1 de 16 bits, si se recibe un mensaje de Windows para un proceso para el que está en curso una operación de bloqueo, existe el riesgo de que la aplicación intente emitir otra llamada a Windows Sockets. Debido a la dificultad de administrar esta condición de forma segura, Windows Sockets 1.1 no admite este comportamiento de la aplicación. No se permite que una aplicación realice más de una llamada de función anidada de Windows Sockets. Solo se permite una llamada de función pendiente para una tarea determinada. Las únicas excepciones son dos funciones que se proporcionan para ayudar al programador en esta situación: WSAIsBlocking y WSACancelBlockingCall.

Se puede llamar a la función WSAIsBlocking en cualquier momento para determinar si una llamada a Windows Sockets 1.1 está en curso o no. Del mismo modo, se puede llamar a la función WSACancelBlockingCall en cualquier momento para cancelar una llamada de bloqueo en curso. Cualquier otro anidamiento de funciones de Windows Sockets produce el error WSAEINPROGRESS.

Se debe destacar que esta restricción se aplica tanto a las operaciones de bloqueo como de no bloqueo. En el caso de las aplicaciones de Windows Sockets 2 que negocian la versión 2.0 o posterior en el momento de llamar a WSAStartup, no hay ninguna restricción en el anidamiento de las operaciones. Las operaciones se pueden anidar en circunstancias poco frecuentes, como durante una devolución de llamada de aceptación condicional de WSAAccept , o si un proveedor de servicios invoca a su vez una función de Windows Sockets 2.

Aunque este mecanismo es suficiente para aplicaciones sencillas, no puede admitir los requisitos complejos de distribución de mensajes de aplicaciones más avanzadas (por ejemplo, aquellos que usan el modelo MDI). Para estas aplicaciones, la API de Windows Sockets incluye la función WSASetBlockingHook, que permite a la aplicación especificar una rutina especial a la que se puede llamar en lugar de la rutina de envío de mensajes predeterminada descrita en la discusión anterior.

El proveedor de Windows Sockets llama al enlace de bloqueo solo si se cumplen todas las siguientes condiciones:

  • La rutina es una que se define como capaz de bloquear.
  • El socket especificado es un socket de bloqueo.
  • La solicitud no se puede completar inmediatamente.

Un socket se establece en bloqueo de forma predeterminada, pero la función ioctlsocket con el IOCTL fiONBIO o la función WSAAsyncSelect puede establecer un socket en modo de bloqueo.

Nunca se llama al enlace de bloqueo y la aplicación no tiene que preocuparse por los problemas de reintrosistencia que el enlace de bloqueo puede introducir, si una aplicación sigue estas directrices:

  • Usa solo sockets sin bloqueo.
  • Usa las rutinas WSAAsyncSelect y/o WSAAsyncGetXByY en lugar de seleccionar y las rutinas getXbyY .

Si una aplicación de Windows Sockets 1.1 invoca una operación asincrónica o sin bloqueo que toma un puntero a un objeto de memoria (un búfer o una variable global, por ejemplo) como argumento, es responsabilidad de la aplicación asegurarse de que el objeto está disponible para Windows Sockets a lo largo de la operación. La aplicación no debe invocar ninguna función de Windows que pueda afectar a la asignación o a la viabilidad de la memoria implicada.