La Red de Conocimientos Pedagógicos - Currículum vitae - Modo sin bloqueo del socket C++

Modo sin bloqueo del socket C++

1. Prólogo

Al aprender sockets en los primeros días, para facilitar la comprensión, a menudo se utiliza el modo de bloqueo predeterminado. Al realizar proyectos, debemos considerar la concurrencia del programa. El modo sin bloqueo juega un papel muy importante y es uno de los puntos que debemos conocer. Este artículo no explica los conceptos de IO con bloqueo y IO sin bloqueo. Si no lo comprende, compréndalo usted mismo. El siguiente código toma la plataforma Linux como ejemplo.

2. Configure el modo sin bloqueo

Configure el modo sin bloqueo mediante el método fcntl Para guardar otras configuraciones del socket, generalmente elige obtener el estado. primero y establezca O_NONBLOCK en función de él, el código es el siguiente:

El valor de retorno de fcntl Failure es -1 y errno se establecerá en el código de error correspondiente. (Errno no se explicará aquí. Si no lo comprende, puede descubrirlo usted mismo). Teniendo en cuenta la situación de falla, personalmente noté que algunos ejemplos en Internet (incluido el proyecto ss-libev) daban a las banderas un valor predeterminado. valor después de que F_GETFL falló El código es el siguiente:

Después de la prueba, de forma predeterminada, el valor obtenido por las banderas es 2, que es O_RDWR de lectura y escritura, y la macro relacionada correspondiente a 0 es O_RDONLY de lectura. sólo, lo que obviamente no es razonable. Personalmente, creo que para un socket normal, la posibilidad de que se produzca un error F_GETFL es pequeña, al menos yo no lo he encontrado. Si algo realmente sale mal, se recomienda seguir el proceso de error en lugar de dar un valor predeterminado.

3. Servidor sin bloqueo

Generalmente, después de que el servidor acepta, configuramos el fd conectado al cliente como sin bloqueo. Después de configurar O_NONBLOCK, la recepción y el envío cambiaron. En el modo de bloqueo predeterminado, cuando recv no tiene datos para recibir (la otra parte no ha enviado datos, o los datos en el búfer se han leído y la otra parte no ha continuado enviando), recv bloqueará y esperará hasta que se envíen los datos. enviado la próxima vez. En el modo sin bloqueo, cuando recv no tiene datos para recibir, recv devolverá directamente -1 y errno se establecerá en EAGAIN/EWOULDBLOCK. De la misma manera, el envío sin bloqueo también devolverá directamente -1 y establecerá errno cuando el búfer de la otra parte esté lleno, en lugar de bloquear y esperar. El código del servidor en modo sin bloqueo es aproximadamente el siguiente:

4. Cliente sin bloqueo

Además de enviar/recibir, el cliente también puede configurar el modo sin bloqueo antes de conectarse, para que pueda regresar directamente.

Cuando el cliente se conecta sin bloqueo, si devuelve 0, significa que la conexión fue exitosa. Si devuelve -1, debe determinar si errno es EINPROGRESS significa que la conexión sin bloqueo. no se puede obtener el resultado de la conexión inmediatamente. Puede usar select/ later. poll/epoll, etc. para juzgar la capacidad de escritura del socket. Si el socket se puede escribir, use getsockopt(iSocket, SOL_SOCKET, SO_ERROR,&err, &len) para juzgar. . . Parece bastante problemático, cierto, pero aún así recomiendo configurar el no bloqueo antes de conectarse en la mayoría de los proyectos (no importa para dispositivos y similares, se debe garantizar la eficiencia en el proyecto). Si usa el modo de bloqueo, puede haber problemas:

Lo siguiente es parte del código para la conexión sin bloqueo. En cuanto a poll/epoll, busque el código usted mismo. ver con lógica sin bloqueo: