2010-02-10 9 views
8

En mi código de cliente, estoy siguiendo estos pasos para conectarse a una toma de corriente:Reutilizando descriptor de socket en caso de fallo de conexión

  1. Creación de una toma de

    sockDesc = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) 
    
  2. Conectándolo (reintento para 'x "tiempo en caso de fallo)

    connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) 
    

    (Después de llenar los destAddr campos)

  3. uso de la toma de send()/recv() operación:

    send(sockDesc, buffer, bufferLen, 0) 
    recv(sockDesc, buffer, bufferLen, 0) 
    
  4. close() el descriptor de socket y salida

    close(sockDesc) 
    

Si durante send()/recv() se rompe la conexión, me encontré con que Podría conectar volviendo al paso 2.

¿Está bien esta solución? ¿Debo cerrar el descriptor de socket y volver al paso 1?

Otra observación interesante que no puedo entender es cuando detengo mi servidor de eco e inicio el cliente. Creo un Socket (paso 1) y llamo al connect() que falla (como se esperaba) pero luego sigo llamando al connect(), digamos, 10 veces. Después de 5 intentos, inicio el servidor y el connect() es exitoso. Pero durante la llamada send() recibe SIGPIPE error. Me gustaría saber:

1) ¿Debo crear un nuevo socket cada vez que connect() falla? Según mi entender, siempre y cuando no haya realizado ningún send()/recv() en el zócalo, es tan bueno como nuevo y puedo reutilizar el mismo fd para la llamada connect().

2) No entiendo por qué se recibe SIGPIPE cuando el servidor está activo y connect() tiene éxito.

+0

Después de cambiar el código según lo sugerido cerrando-descriptor scoket y crear un nuevo socket y conectarlo, el problema SIGPIPE ya no está ocurriendo. – Adil

+1

Encontré este enlace útil y relacionado con tu pregunta como el utilizado envía en lugar de escribir: http://stackoverflow.com/questions/9048959/write-and-send-solving-errors-difference –

Respuesta

5

Sí, debe cerrar y volver al paso 1:

close() cierra un descriptor de archivo, de modo que ya no se refiere a cualquier archivo y puede ser reutilizado.

De here.

+0

¿Alguna razón específica? Como estoy usando el mismo fd en la llamada de conexión para volver a conectarme con el servidor y no crear ningún nuevo socket, ¿no debería perjudicarme? o en este caso el conector entra en estado de espera o algo así? – Adil

+0

Bueno, las especificaciones sugieren que el "archivo" ya no se refiere a nada. Para mí, esto indica que el identificador aún es válido, pero necesita ser reinicializado. –

4

Las tomas correspondientes a la conexión interrumpida están en estado inestable. normalmente no podrá volver a conectarse a menos que el sistema operativo lo libere.

Creo que será mejor cerrar() y volver a conectar ... no es necesario crear otro socket.

De todos modos, asegúrese de establecer LINGER de su zócalo para asegurarse de que no se pierden datos en la transmisión.

Ver http://www.gnu.org/s/libc/manual/html_node/Socket_002dLevel-Options.html#Socket_002dLevel-Options

+0

Si cierro el descriptor, creo que necesito volver a crear el socket porque cerrar el descriptor significa destruir el socket, ¿no? – Adil

+0

Después de que un socket haya sido 'close()' d, ya no deberá usar el descriptor de socket. No es válido entonces. Use 'socket()' para adquirir un nuevo descriptor de socket. – alk

2

Si la conexión se interrumpió y se intenta escribir en el descriptor de fichero que debe obtener el error tubería/señal rota. Todo esto está diciendo que el descriptor de archivo que intentó escribir ya no tiene a nadie del otro lado para leer lo que está enviando.

Lo que puedes hacer es tomar la señal SIGPIPE y luego tratar con la reconexión cerrando el FD y volviendo al paso 1. Ahora tendrás un nuevo FD del que puedes leer y escribir para la conexión.

2

Si la Especificación UNIX única no dice que DEBE funcionar para volver al paso # 2 en lugar del paso # 1, entonces el hecho de que funcione en Linux es solo un detalle de implementación, y usted estaría mucho mejor y más portátil si vuelves al paso n. ° 1. Por lo que sé, la especificación no garantiza que esté bien volver al paso 2 y, por lo tanto, le aconsejo que vuelva al paso 1.

4

Creo que cerrar el socket es lo correcto, a pesar de que puede funcionar si no lo hace.

Un zócalo que no se ha podido conectar puede no estar EXACTAMENTE en el mismo estado que uno nuevo, lo que podría causar problemas más adelante. Prefiero evitar la posibilidad y solo hacer una nueva. Es más limpio.

Los sockets TCP tienen MUCHO estado, algunos de los cuales son específicos de la implementación y se resuelven desde la red.

Cuestiones relacionadas