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 complete la operación asociada. Se produce un problema cuando la operación tarda mucho tiempo 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 de Sockets de Berkeley 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 pudieron asumir la programación preventiva. Por lo tanto, se recomienda encarecidamente que los programadores usen las operaciones de no bloqueo (asincrónica) 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 preventivos 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 (enlazar, getockopty getpeername por ejemplo, se completan inmediatamente. No hay ninguna diferencia entre un bloqueo y una operación de no 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 pseudo-bloqueo como se indica a continuación.
El proveedor de servicios inicia la operación y, a continuación, entra en un bucle en el que envía los mensajes de Windows (lo que produce 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ónWSAIsBlocking 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ónWSACancelBlockingCall en cualquier momento para cancelar una llamada de bloqueo en curso. Se produce un error en cualquier otro anidamiento de funciones de Windows Sockets con el error WSAEINPROGRESS.
Debe destacarse 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 un WSAAccept devolución de llamada de aceptación condicional, o si un proveedor de servicios a su vez invoca una función de Windows Sockets 2.
Aunque este mecanismo es suficiente para aplicaciones sencillas, no puede admitir los requisitos complejos de envío 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 distribución 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 FIONBIO IOCTL 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 necesita preocuparse por los problemas de reintrosistencia que puede introducir el enlace de bloqueo, si una aplicación sigue estas directrices:
- Usa solo sockets que no son de bloqueo.
- Usa la WSAAsyncSelect o las rutinas de WSAAsyncGetXByY en lugar de seleccionar y las rutinas de 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 durante toda la operación. La aplicación no debe invocar ninguna función de Windows que pueda afectar a la asignación o abordar la viabilidad de la memoria implicada.