2009-11-25 26 views
7

En la programación de socket en Linux necesito escribir datos en el socket pero no sé si el socket está abierto o cerrado. ¿Cómo sé que el socket está abierto y cerrado sin leer?Comprobar conexión abierta o cerrada? (En C en Linux)

printf("befor read%d\n", n); 
bzero(buffer, MAX_SIZE_BUFFER); 
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1); 
printf("after read%d\n", n); 
if (n <= 0) 
{ 
    break; 
} 
printf("befor write%d, s: %d \n", n , sockfd); 

n = write(newsockfd, buffer, n); 
if (n <= 0) 
{ 
    break; 
} 

he leído de sockfd y estoy segura que esta conexión está abierta. ¿Cuándo escribir búfer en newsockfd? No sé si newsockfd está abierto o cerrado. ¿Cómo comprobar que newsockfd está cerrado?


Sé el problema. en el medio de escribir la conexión cerrada. por ejemplo, escribir 1024 datos en 500 conexión cerrada y programa cerrado. cómo evitar esto?

Respuesta

11

utilizo send() en lugar de escribir() que manejan ninguna señal:

bzero(buffer, MAX_SIZE_BUFFER); 
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1); 
printf("after read%d\n", n); 
if (n <= 0) 
{ 
    break; 
} 
n2 = send(newsockfd, buffer, n, MSG_NOSIGNAL); 
if (n2 == -1) 
{ 
    close(sockfd); 
    close(newsockfd); 
    return; 
} 
if (n2 != n) 
{ 
    break; 
} 
+0

Esto funcionará, y la otra alternativa es usar 'sigaction' para ignorar' SIGPIPE' (establezca su manejador en 'SIG_IGN'). – caf

15

La manera de comprobar si se puede escribir en una toma de corriente está, sorprendentemente, para tratar de escribir en él :-)

Si la toma se ha cerrado, obtendrá un código -1 regreso de write y puede examinar errno para ver cuál era el problema.

Si el enchufe sigue siendo válida, pero que simplemente no puede escribir datos en el momento, write volverá 0. La llamada read también se comporta de una manera similar, volviendo -1 si hay un problema.

Básicamente, por write:

  • si vuelves un -1, ha habido un problema y se debe comprobar errno para ver si es recuperable o fatal.
  • Si devuelve un 0, entonces no puede escribir nada en este momento (puede ser una acumulación de red o algún otro problema, pero definitivamente no (todavía) fatal).
  • Si obtiene un valor menor que el que deseaba, se ha enviado algunos de los datos. Ajuste sus punteros para que pueda enviar el resto en el próximo ciclo. Do no Supongamos que un valor de retorno positivo significa que se ha enviado todo el bloque.
  • Si obtiene el mismo número que el número de bytes que intentó enviar, se ha aceptado la totalidad del búfer para la entrega.
  • Si devuelve más de lo que pidió que le enviaran, envíe un correo electrónico a los desarrolladores del kernel con un comentario mordaz. Linus et al amará que :-)

Actualización: como CAF ha señalado en los comentarios, me olvidé de tomar en cuenta el manejo de señales. Debe ignorar la señal de tubería rota o write fallará internamente al elevar esa señal.

Usted puede hacer esto mediante la inserción:

struct sigaction new_actn, old_actn; 
new_actn.sa_handler = SIG_IGN; 
sigemptyset (&new_actn.sa_mask); 
new_actn.sa_flags = 0; 
sigaction (SIGPIPE, &new_actn, &old_actn); 

antes de comenzar a utilizar las funciones de socket. A continuación, puede utilizar:

sigaction (SIGPIPE, &old_actn, NULL); 

para restaurar la gestión de señal anterior.

+0

en la siguiente línea ver si (n <= 0), pero en función de escritura se produjo algún error y cerca programa – SjB

+0

@SjB, * no * asume problemas si 'write' devuelve 0. Esto puede suceder si hay una acumulación temporal de la red. Si la acumulación se convierte en un problema real, la sesión se cerrará y eventualmente obtendrá -1. Hasta entonces, solo sigue intentándolo. – paxdiablo

+0

Sé el problema. en el medio de escribir la conexión cerrada. por ejemplo, escribir 1024 datos en 500 conexión cerrada y programa cerrado – SjB

4

La programación de zócalos puede ser un tanto complicada, porque a menudo no se sabe que ha ocurrido un error hasta mucho más tarde.

Por ejemplo, si la máquina que está escribiendo se apaga anormalmente, la llamada de escritura puede tener éxito (porque usted pudo escribir en las memorias intermedias internas del sistema operativo), solo para fallar durante la llamada de cierre.

A menos que tenga una forma de capa de aplicación que verifique que el socket está activo (es decir, enviando un mensaje y requiriendo una respuesta dentro de un período de tiempo) no tiene forma de saberlo. Si está utilizando un protocolo estándar, es posible que ya exista algo para manejar los errores.

Por lo tanto, la respuesta breve es que debe verificar los retornos de error de casi todas las llamadas que tocan el socket (leer, escribir, cerrar, etc.).

+2

Desafortunadamente esta es la respuesta correcta. Intenté algunas formas de averiguar si las conexiones HTTP Keep-alive siguen siendo válidas, pero no son confiables y no tienen condiciones de carrera. – Lothar

Cuestiones relacionadas