2011-11-24 12 views
10

Hola, estoy leyendo TLPI (The Linux Programming Interface), tengo una pregunta sobre connect().¿Conecta() el bloque para el zócalo TCP?

Según tengo entendido, connect() volverá inmediatamente si los números de conexión pendientes de listen() no alcanzan el "retraso acumulado". Y bloqueará de lo contrario. (según la figura 56-2)

Pero para el socket TCP, siempre bloqueará hasta que se llame a accept() en el lado del servidor (de acuerdo con la figura 61-5).

¿Es correcto? Porque vi eso en el código de ejemplo (p.1265), llama a listen() para escuchar un puerto específico y luego llama a connect() a ese puerto ANTES de llamar a accept().

Por lo tanto, conectar bloques() para siempre en este caso, ¿no?

Gracias!

+0

Si eso es lo que realmente muestra la figura 56-2, está mal. – EJP

Respuesta

19

Casi no existe una conexión "inmediata", las cosas pueden perderse en el camino, y una operación que debe realizarse inmediatamente en teoría podría no hacerlo en la práctica, y en cualquier caso hay un tiempo de transmisión de extremo a extremo.

Sin embargo

  • connect() en un socket TCP es una operación de bloqueo a menos que el descriptor de socket se pone en modo de no bloqueo.

  • El sistema operativo se encarga del protocolo de enlace TCP, cuando finaliza el intercambio, connect() regresa. (es decir, connect() no se bloquea hasta que las otras llamadas finales acepten())

  • Un protocolo de enlace TCP satisfactorio se pondrá en la cola de la aplicación del servidor y se puede aceptar() 'ed cualquier momento posterior.

+0

Solo quería agregar que 'connect' solo espera el handshake y no que el servidor llame' accept', es por dos razones: la primera es que desde el lado del cliente está conectado después del handshake; El segundo es porque puede pasar un tiempo arbitrario entre el protocolo de enlace y antes de que los servidores llamen 'accept', lo que de hecho puede ser para siempre. –

+1

Incluso sin el resto de la respuesta, "casi no hay 'inmediatamente'" solo que justifique un +1. Esto es tan cierto para muchas operaciones, incluso en modo no bloqueante. Inmediatamente puede ser, de manera sorprendente, un largo tiempo a veces, incluso para cosas en las que realmente no lo esperarías. – Damon

+0

@JoachimPileborg @nos Si 'connect()' regresa antes de que el servidor llame a 'accept()', ¿qué ocurre si el cliente intenta 'send()' antes de que el servidor haya llamado 'accept()'? – Flash

3

connect es una llamada de bloqueo por defecto, pero puede hacer que no bloquee pasando a socket la bandera SOCK_NONBLOCK.

+4

O más comúnmente, usando la función de socket BSD "tradicional" de fcntl con O_NONBLOCK. SOCK_NONBLOCK es específico de Linux. – MarkR

2

connect() bloquea hasta finalizar el protocolo de enlace de 3 vías TCP. El apretón de manos en el lado de escucha se maneja mediante la pila TCP/IP en el kernel y finaliza sin notificar el proceso del usuario. Solo después de que se complete el protocolo de enlace (y el iniciador puede regresar desde la llamada a connect() ya), accept() en el proceso de usuario puede seleccionar un nuevo socket y regresar. No esperar aceptar() es necesario para completar el saludo.

El motivo es simple: si tiene un proceso de subproceso único para escuchar las conexiones y requiere esperar a aceptar() para establecer las conexiones, no puede responder a las SYN de TCP mientras procesa otra solicitud. La pila TCP en el lado de inicio retransmitirá, pero en servidores moderadamente cargados, las posibilidades son altas, este paquete retransmitido todavía llegará, mientras que no aceptará() pendiente y se eliminará nuevamente, lo que provocará desagradables retrasos y tiempos de espera de conexión.

Cuestiones relacionadas