2012-10-07 49 views
5

Estoy escribiendo un servidor en Linux que tendrá que soportar operaciones simultáneas de lectura/escritura de múltiples clientes. Deseo utilizar la función de seleccionar para administrar la disponibilidad de lectura/escritura.¿Cuál es el beneficio de usar sockets no bloqueantes con la función "seleccionar"?

Lo que no entiendo es esto: supongamos que quiero esperar hasta que un socket tenga datos disponibles para leer. La documentación para seleccione indica que bloquea hasta que haya datos disponibles para leer y que la función de lectura no se bloquee.

Así que si estoy usando seleccionar y sé que la función de lectura no se bloqueará, ¿por qué tendría que configurar mis sockets para que no sean bloqueados?

Respuesta

6

Puede haber casos en los que se informa que un socket está listo pero en el momento en que lo verifica, cambia su estado.

Uno de los buenos ejemplos es aceptar conexiones. Cuando llega una nueva conexión, se informa que un zócalo de escucha está listo para su lectura. Cuando llegue el momento de llamar a accept, la otra parte podría cerrar la conexión antes de enviar algo y antes de llamar al accept. Por supuesto, el manejo de este caso depende del sistema operativo, pero es posible que accept simplemente bloquee hasta que se establezca una nueva conexión, lo que hará que nuestra aplicación espere un tiempo indefinido para evitar el procesamiento de otros zócalos. Si su toma de audición está en un modo sin bloqueo, esto no sucederá y obtendrá EWOULDBLOCK o algún otro error, pero accept no se bloqueará de todos modos.

Algunos núcleos solían tener (espero que se solucione ahora) un error interesante con UDP y select. Cuando llega un datagrama, select se activa con el socket con el datagrama marcado como listo para leer. La validación de la suma de comprobación del datagrama se pospone hasta que un código de usuario llame al recvfrom (o alguna otra API capaz de recibir datagramas UDP). Cuando el código llama al recvfrom y el código de validación detecta una discrepancia en la suma de comprobación, simplemente se descarta un datagrama y recvfrom termina bloqueándose hasta que llega un siguiente datagrama. Uno de los parches que resuelve este problema (junto con la descripción del problema) se puede encontrar en here.

2

Una de las ventajas es que detectará cualquier error de programación que realice, ya que si intenta leer un conector que normalmente lo bloquearía, obtendrá EWOULDBLOCK en su lugar. Para objetos que no sean sockets, el comportamiento exacto de la API puede cambiar, consulte http://www.scottklement.com/rpg/socktut/nonblocking.html.

+0

Aha, gracias por eso. :) – CaptainCodeman

1

Esto suena sarcástico pero no lo es. La mejor razón para hacer que no bloqueen es para que no bloquees.

Piénselo. select() le dice que hay algo para leer pero no sabe cuánto. Podría ser de 2 bytes, podría ser 2.000. En la mayoría de los casos, es más eficiente drenar cualquier información que exista antes de volver al select. Entonces ingresa un ciclo while para leer

while (1) 
{ 
    n = read(sock, buffer, 200); 
    //check return code, etc 
} 

¿Qué sucede en la última lectura cuando no queda nada por leer? Si el zócalo no está bloqueando, bloqueará, derrotando (al menos parcialmente) el punto del select().

3

Además de los errores del kernel mencionados por otros, una razón diferente para elegir enchufes sin bloqueo, incluso con un bucle de sondeo, es que permite un mayor rendimiento con datos que llegan rápidamente. Piense qué sucede cuando un socket de bloqueo se marca como "legible". No tiene idea de la cantidad de datos que ha llegado, por lo que puede leerlos de manera segura solo una vez.Luego debe regresar al ciclo de eventos para que su sondeador verifique si el socket todavía es legible. Esto significa que para cada lectura o escritura en el socket debe realizar al menos dos llamadas al sistema: select para indicar que es seguro de leer, y la lectura/escritura misma.

Con tomas sin bloqueo puede omitir las llamadas innecesarias al select después de la primera. Cuando un socket se marca como legible por select, tiene la opción de leer de él siempre y cuando devuelva datos, lo que permite un procesamiento más rápido de ráfagas rápidas de datos.

+0

Gracias, muy buen punto, no sabía que tratar de leer sería más rápido que otro. – CaptainCodeman

Cuestiones relacionadas