Escribir en un socket TCP local cerrado que no falla

18 minutos de lectura

avatar de usuario
Freír regular

Parece que tengo un problema con mis enchufes. A continuación, verá un código que bifurca un servidor y un cliente. El servidor abre un socket TCP y el cliente se conecta a él y luego lo cierra. Los sueños se utilizan para coordinar el tiempo. Después del cierre() del lado del cliente, el servidor intenta escribir() en su propio extremo de la conexión TCP. De acuerdo con la página del manual write(2), esto deberían dame un SIGPIPE y un EPIPE errno. Sin embargo, no veo esto. Desde el punto de vista del servidor, la escritura en un socket local cerrado tiene éxitoy en ausencia del EPIPE, no puedo ver cómo el servidor debería detectar que el cliente ha cerrado el socket.

En el intervalo entre el cliente que cierra su extremo y el servidor que intenta escribir, una llamada a netstat mostrará que la conexión está en un estado CLOSE_WAIT/FIN_WAIT2, por lo que el extremo del servidor definitivamente debería poder rechazar la escritura.

Como referencia, estoy en Debian Squeeze, uname -r es 2.6.39-bpo.2-amd64.

¿Que está pasando aqui?


#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>

#include <netdb.h>

#define SERVER_ADDRESS "127.0.0.7"
#define SERVER_PORT 4777


#define myfail_if( test, msg ) do { if((test)){ fprintf(stderr, msg "\n"); exit(1); } } while (0)
#define myfail_unless( test, msg ) myfail_if( !(test), msg )

int connect_client( char *addr, int actual_port )
{
    int client_fd;

    struct addrinfo hint;
    struct addrinfo *ailist, *aip;


    memset( &hint, '\0', sizeof( struct addrinfo ) );
    hint.ai_socktype = SOCK_STREAM;

    myfail_if( getaddrinfo( addr, NULL, &hint, &ailist ) != 0, "getaddrinfo failed." );

    int connected = 0;
    for( aip = ailist; aip; aip = aip->ai_next ) {
        ((struct sockaddr_in *)aip->ai_addr)->sin_port = htons( actual_port );
        client_fd = socket( aip->ai_family, aip->ai_socktype, aip->ai_protocol );

        if( client_fd == -1) { continue; }
        if( connect( client_fd, aip->ai_addr, aip->ai_addrlen) == 0 ) {
            connected = 1;
            break;
        }
        close( client_fd );
    }

    freeaddrinfo( ailist );

    myfail_unless( connected, "Didn't connect." );
    return client_fd;
}


void client(){
    sleep(1);
    int client_fd = connect_client( SERVER_ADDRESS, SERVER_PORT );

    printf("Client closing its fd... ");
    myfail_unless( 0 == close( client_fd ), "close failed" );
    fprintf(stdout, "Client exiting.\n");
    exit(0);
}


int init_server( struct sockaddr * saddr, socklen_t saddr_len )
{
    int sock_fd;

    sock_fd = socket( saddr->sa_family, SOCK_STREAM, 0 );
    if ( sock_fd < 0 ){
        return sock_fd;
    }

    myfail_unless( bind( sock_fd, saddr, saddr_len ) == 0, "Failed to bind." );
    return sock_fd;
}

int start_server( const char * addr, int port )
{
    struct addrinfo *ailist, *aip;
    struct addrinfo hint;
    int sock_fd;

    memset( &hint, '\0', sizeof( struct addrinfo ) );
    hint.ai_socktype = SOCK_STREAM;
    myfail_if( getaddrinfo( addr, NULL, &hint, &ailist ) != 0, "getaddrinfo failed." );

    for( aip = ailist; aip; aip = aip->ai_next ){
        ((struct sockaddr_in *)aip->ai_addr)->sin_port = htons( port );
        sock_fd = init_server( aip->ai_addr, aip->ai_addrlen );
        if ( sock_fd > 0 ){
            break;
        } 
    }
    freeaddrinfo( aip );

    myfail_unless( listen( sock_fd, 2 ) == 0, "Failed to listen" );
    return sock_fd;
}


int server_accept( int server_fd )
{
    printf("Accepting\n");
    int client_fd = accept( server_fd, NULL, NULL );
    myfail_unless( client_fd > 0, "Failed to accept" );
    return client_fd;
}


void server() {
    int server_fd = start_server(SERVER_ADDRESS, SERVER_PORT);
    int client_fd = server_accept( server_fd );

    printf("Server sleeping\n");
    sleep(60);

    printf( "Errno before: %s\n", strerror( errno ) );
    printf( "Write result: %d\n", write( client_fd, "123", 3 ) );
    printf( "Errno after:  %s\n", strerror( errno ) );

    close( client_fd );
}


int main(void){
    pid_t clientpid;
    pid_t serverpid;

    clientpid = fork();

    if ( clientpid == 0 ) {
        client();
    } else {
        serverpid = fork();

        if ( serverpid == 0 ) {
            server();
        }
        else {
            int clientstatus;
            int serverstatus;

            waitpid( clientpid, &clientstatus, 0 );
            waitpid( serverpid, &serverstatus, 0 );

            printf( "Client status is %d, server status is %d\n", 
                    clientstatus, serverstatus );
        }
    }

    return 0;
}

  • no estás configurando ai_family = AF_INETpero asumes que obtienes un sockaddr_in devuelto Es probable que se rompa en algún momento en el futuro.

    – Por Johansson

    11 de julio de 2012 a las 17:46

  • A riesgo de no responder la pregunta, ¿por qué confía en una escritura () para ver si la conexión está cerrada? ¿Has mirado select() y/o poll()? Al bloquear en accept(), siempre acepta la primera conexión a su puerto, ya sea la conexión que desea o no.

    – ChrisH

    12 de julio de 2012 a las 0:01

  • ¿Has probado un shutdown() en el socket del lado del cliente antes de llamar close()?

    – alk

    12 de julio de 2012 a las 8:16

  • @ChrisH: Obtengo un resultado similar con select(), cerrar el socket desde el extremo del cliente es invisible para el servidor. No hace que select() devuelva el fd en ninguno de los tres estados.

    – freír regular

    12 de julio de 2012 a las 8:20

  • @regularfry, el socket debe devolverse en el conjunto de lectura de select, ya que obtiene EOF en la lectura.

    – Por Johansson

    15 de julio de 2012 a las 17:21

avatar de usuario
jxh

Esto es lo que dice la página de manual de Linux sobre write y EPIPE:

   EPIPE  fd is connected to a pipe or socket whose reading end is closed.
          When this happens the writing process will also receive  a  SIG-
          PIPE  signal.  (Thus, the write return value is seen only if the
          program catches, blocks or ignores this signal.)

Cuando Linux está usando un pipe o un socketpairpuede y comprobará la final de lectura de la pareja, como demostrarían estos dos programas:

void test_socketpair () {
    int pair[2];
    socketpair(PF_LOCAL, SOCK_STREAM, 0, pair);
    close(pair[0]);
    if (send(pair[1], "a", 1, MSG_NOSIGNAL) < 0) perror("send");
}

void test_pipe () {
    int pair[2];
    pipe(pair);
    close(pair[0]);
    signal(SIGPIPE, SIG_IGN);
    if (write(pair[1], "a", 1) < 0) perror("send");
    signal(SIGPIPE, SIG_DFL);
}

Linux puede hacerlo porque el kernel tiene un conocimiento innato sobre el otro extremo de la tubería o el par conectado. Sin embargo, al usar connect, la pila de protocolos mantiene el estado del socket. Su prueba demuestra este comportamiento, pero a continuación hay un programa que lo hace todo en un solo hilo, similar a las dos pruebas anteriores:

int a_sock = socket(PF_INET, SOCK_STREAM, 0);
const int one = 1;
setsockopt(a_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
struct sockaddr_in a_sin = {0};
a_sin.sin_port = htons(4321);
a_sin.sin_family = AF_INET;
a_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
bind(a_sock, (struct sockaddr *)&a_sin, sizeof(a_sin));
listen(a_sock, 1);
int c_sock = socket(PF_INET, SOCK_STREAM, 0);
fcntl(c_sock, F_SETFL, fcntl(c_sock, F_GETFL, 0)|O_NONBLOCK);
connect(c_sock, (struct sockaddr *)&a_sin, sizeof(a_sin));
fcntl(c_sock, F_SETFL, fcntl(c_sock, F_GETFL, 0)&~O_NONBLOCK);
struct sockaddr_in s_sin = {0};
socklen_t s_sinlen = sizeof(s_sin);
int s_sock = accept(a_sock, (struct sockaddr *)&s_sin, &s_sinlen);
struct pollfd c_pfd = { c_sock, POLLOUT, 0 };
if (poll(&c_pfd, 1, -1) != 1) perror("poll");
int erropt = -1;
socklen_t errlen = sizeof(erropt);
getsockopt(c_sock, SOL_SOCKET, SO_ERROR, &erropt, &errlen);
if (erropt != 0) { errno = erropt; perror("connect"); }
puts("P|Recv-Q|Send-Q|Local Address|Foreign Address|State|");
char cmd[256];
snprintf(cmd, sizeof(cmd), "netstat -tn | grep ':%hu ' | sed 's/  */|/g'",
         ntohs(s_sin.sin_port));
puts("before close on client"); system(cmd);
close(c_sock);
puts("after close on client"); system(cmd);
if (send(s_sock, "a", 1, MSG_NOSIGNAL) < 0) perror("send");
puts("after send on server"); system(cmd);
puts("end of test");
sleep(5);

Si ejecuta el programa anterior, obtendrá un resultado similar a este:

P|Recv-Q|Send-Q|Local Address|Foreign Address|State|
before close on client
tcp|0|0|127.0.0.1:35790|127.0.0.1:4321|ESTABLISHED|
tcp|0|0|127.0.0.1:4321|127.0.0.1:35790|ESTABLISHED|
after close on client
tcp|0|0|127.0.0.1:35790|127.0.0.1:4321|FIN_WAIT2|
tcp|1|0|127.0.0.1:4321|127.0.0.1:35790|CLOSE_WAIT|
after send on server
end of test

Esto muestra que tomó uno write para que los enchufes hagan la transición al CLOSED estados Para averiguar por qué ocurrió esto, un volcado TCP de la transacción puede ser útil:

16:45:28 127.0.0.1 > 127.0.0.1
 .809578 IP .35790 > .4321: S 1062313174:1062313174(0) win 32792 <mss 16396,sackOK,timestamp 3915671437 0,nop,wscale 7>
 .809715 IP .4321 > .35790: S 1068622806:1068622806(0) ack 1062313175 win 32768 <mss 16396,sackOK,timestamp 3915671437 3915671437,nop,wscale 7>
 .809583 IP .35790 > .4321: . ack 1 win 257 <nop,nop,timestamp 3915671437 3915671437>
 .840364 IP .35790 > .4321: F 1:1(0) ack 1 win 257 <nop,nop,timestamp 3915671468 3915671437>
 .841170 IP .4321 > .35790: . ack 2 win 256 <nop,nop,timestamp 3915671469 3915671468>
 .865792 IP .4321 > .35790: P 1:2(1) ack 2 win 256 <nop,nop,timestamp 3915671493 3915671468>
 .865809 IP .35790 > .4321: R 1062313176:1062313176(0) win 0

Las primeras tres líneas representan el apretón de manos de 3 vías. La cuarta línea es la FIN paquete que el cliente envía al servidor, y la quinta línea es el ACK del servidor, acusando recibo. La sexta línea es el servidor que intenta enviar 1 byte de datos al cliente con el PUSH conjunto de banderas La línea final es el cliente. RESET paquete, lo que hace que se libere el estado TCP para la conexión, y es por eso que el tercer netstat El comando no dio como resultado ningún resultado en la prueba anterior.

Por lo tanto, el servidor no sabe que el cliente restablecerá la conexión hasta que intente enviarle algunos datos. El motivo del reinicio es porque el cliente llamó closeen lugar de otra cosa.

El servidor no puede saber con certeza qué llamada al sistema ha emitido realmente el cliente, solo puede seguir el estado de TCP. Por ejemplo, podríamos reemplazar el close llamar con una llamada a shutdown en lugar de.

//close(c_sock);
shutdown(c_sock, SHUT_WR);

La diferencia entre shutdown y close es eso shutdown sólo rige el estado de la conexión, mientras que close también rige el estado de la descriptor de archivo que representa el zócalo. A shutdown no close un zócalo

La salida será diferente con el shutdown cambiar:

P|Recv-Q|Send-Q|Local Address|Foreign Address|State|
before close on client
tcp|0|0|127.0.0.1:4321|127.0.0.1:56355|ESTABLISHED|
tcp|0|0|127.0.0.1:56355|127.0.0.1:4321|ESTABLISHED|
after close on client
tcp|1|0|127.0.0.1:4321|127.0.0.1:56355|CLOSE_WAIT|
tcp|0|0|127.0.0.1:56355|127.0.0.1:4321|FIN_WAIT2|
after send on server
tcp|1|0|127.0.0.1:4321|127.0.0.1:56355|CLOSE_WAIT|
tcp|1|0|127.0.0.1:56355|127.0.0.1:4321|FIN_WAIT2|
end of test

El volcado de TCP también mostrará algo diferente:

17:09:18 127.0.0.1 > 127.0.0.1
 .722520 IP .56355 > .4321: S 2558095134:2558095134(0) win 32792 <mss 16396,sackOK,timestamp 3917101399 0,nop,wscale 7>
 .722594 IP .4321 > .56355: S 2563862019:2563862019(0) ack 2558095135 win 32768 <mss 16396,sackOK,timestamp 3917101399 3917101399,nop,wscale 7>
 .722615 IP .56355 > .4321: . ack 1 win 257 <nop,nop,timestamp 3917101399 3917101399>
 .748838 IP .56355 > .4321: F 1:1(0) ack 1 win 257 <nop,nop,timestamp 3917101425 3917101399>
 .748956 IP .4321 > .56355: . ack 2 win 256 <nop,nop,timestamp 3917101426 3917101425>
 .764894 IP .4321 > .56355: P 1:2(1) ack 2 win 256 <nop,nop,timestamp 3917101442 3917101425>
 .764903 IP .56355 > .4321: . ack 2 win 257 <nop,nop,timestamp 3917101442 3917101442>
17:09:23
 .786921 IP .56355 > .4321: R 2:2(0) ack 2 win 257 <nop,nop,timestamp 3917106464 3917101442>

Observe que el reinicio al final llega 5 segundos después del último ACK paquete. Este restablecimiento se debe a que el programa se cerró sin cerrar correctamente los enchufes. Es el ACK paquete del cliente al servidor antes del reinicio que es diferente al anterior. Esta es la indicación de que el cliente no usó close. En TCP, el FIN indicación es realmente una indicación de que no hay más datos para enviar. Pero como una conexión TCP es bidireccional, el servidor que recibe la FIN asume que el cliente aún puede recibir datos. En el caso anterior, el cliente sí acepta los datos.

Si el cliente usa close o SHUT_WR emitir un FINen cualquier caso se puede detectar la llegada del FIN sondeando en el socket del servidor para un evento legible. Si después de llamar read el resultado es 0entonces sabes el FIN ha llegado, y puedes hacer lo que quieras con esa información.

struct pollfd s_pfd = { s_sock, POLLIN|POLLOUT, 0 };
if (poll(&s_pfd, 1, -1) != 1) perror("poll");
if (s_pfd.revents|POLLIN) {
    char c;
    int r;
    while ((r = recv(s_sock, &c, 1, MSG_DONTWAIT)) == 1) {}
    if (r == 0) { /*...FIN received...*/ }
    else if (errno == EAGAIN) { /*...no more data to read for now...*/ }
    else { /*...some other error...*/ perror("recv"); }
}

Ahora, es trivialmente cierto que si el servidor emite SHUT_WR con shutdown antes de que intente hacer una escritura, de hecho obtendrá el EPIPE error.

shutdown(s_sock, SHUT_WR);
if (send(s_sock, "a", 1, MSG_NOSIGNAL) < 0) perror("send");

Si, en cambio, desea que el cliente indique un restablecimiento inmediato en el servidor, puede forzar que eso suceda en la mayoría de las pilas de TCP habilitando la opción de permanencia, con un tiempo de espera de permanencia de 0 antes de llamar close.

struct linger lo = { 1, 0 };
setsockopt(c_sock, SOL_SOCKET, SO_LINGER, &lo, sizeof(lo));
close(c_sock);

Con el cambio anterior, la salida del programa se convierte en:

P|Recv-Q|Send-Q|Local Address|Foreign Address|State|
before close on client
tcp|0|0|127.0.0.1:35043|127.0.0.1:4321|ESTABLISHED|
tcp|0|0|127.0.0.1:4321|127.0.0.1:35043|ESTABLISHED|
after close on client
send: Connection reset by peer
after send on server
end of test

los send obtiene un error inmediato en este caso, pero no es EPIPEestá ECONNRESET. El volcado de TCP también refleja esto:

17:44:21 127.0.0.1 > 127.0.0.1
 .662163 IP .35043 > .4321: S 498617888:498617888(0) win 32792 <mss 16396,sackOK,timestamp 3919204411 0,nop,wscale 7>
 .662176 IP .4321 > .35043: S 497680435:497680435(0) ack 498617889 win 32768 <mss 16396,sackOK,timestamp 3919204411 3919204411,nop,wscale 7>
 .662184 IP .35043 > .4321: . ack 1 win 257 <nop,nop,timestamp 3919204411 3919204411>
 .691207 IP .35043 > .4321: R 1:1(0) ack 1 win 257 <nop,nop,timestamp 3919204440 3919204411>

los RESET el paquete llega justo después de que se completa el protocolo de enlace de 3 vías. Sin embargo, usar esta opción tiene sus peligros. Si el otro extremo tiene datos no leídos en el búfer del socket cuando el RESET llega, esos datos se eliminarán y se perderán. forzando un RESET to be sent se usa generalmente en protocolos de estilo de solicitud/respuesta. El remitente de la solicitud puede saber que no puede haber pérdida de datos cuando recibe la respuesta completa a su solicitud. Entonces, es seguro para el remitente de la solicitud forzar una RESET para ser enviado en la conexión.

  • que respuesta ¡Simplemente magnífico!

    – sha

    16 de agosto de 2017 a las 6:59

  • ¿Cómo sé que el extremo de lectura del zócalo está cerrado si se conecta a un servidor remoto?

    – softwarevamp

    17/09/2018 a las 10:22

  • @softwarevamp La respuesta simplemente ilustra con un programa que se conecta en la misma máquina. Pruebe el experimento usted mismo con un servidor remoto y vea que mi respuesta aún se mantiene.

    – jxh

    17 de septiembre de 2018 a las 15:18

  • Una gran respuesta. Nunca supe que eso era lo que hacía la opción de permanencia, tiene mucho sentido ahora.

    – mrdecemberista

    5 de mayo de 2021 a las 12:27

Tiene dos sockets, uno para el cliente y otro para el servidor. Ahora su cliente está realizando el cierre activo. Esto significa que el cliente ha iniciado la finalización de la conexión de TCP (se ha enviado un segmento TCP FIN desde el envío del cliente).

En esta etapa, verá el socket del cliente en el estado FIN_WAIT1. Ahora, ¿cuál es el estado del socket del servidor ahora? Está en estado CLOSE_WAIT. Por lo tanto, el socket del servidor no está cerrado.

El FIN del servidor aún no se ha enviado. (Por qué, ya que la aplicación no ha cerrado el zócalo). En esta etapa, está escribiendo sobre el socket del servidor para que no obtenga un error.

Ahora, si desea ver el error, simplemente escriba close(client_fd) antes de escribir sobre el socket.

close(client_fd);
printf( "Write result: %d\n", write( client_fd, "123", 3 ) );

Aquí, el socket del servidor ya no está en estado CLOSE_WAIT, por lo que puede ver que el valor de retorno de escritura es -ve para indicar el error. Espero que esto aclare.

  • Esta es la respuesta correcta, pero creo que podrías ser un poco más claro. El lado del cliente no puede cerrar la escritura en el lado del servidor, solo la lectura. Sin embargo, el cliente no podrá leer nada de lo que escribe el servidor. Además, después de llamar close en el lado del servidor, el fd no será válido. Si está utilizando subprocesos, otro subproceso podría haberlo reclamado. Vocación write después close es una muy mala idea.

    – Por Johansson

    11 de julio de 2012 a las 17:57

  • Gracias Per, por tu observación. He escrito close(client_fd) en el servidor, solo para explicar la causa de que no haya un error. Y sí, en este caso, para hacer que el cliente lea algo, en lugar de cerrar necesitamos usar shutdown (con SHUT_WR) que permitir que el cliente lea.

    – Tanmoy Bandyopadhyay

    11 de julio de 2012 a las 18:15


  • @Tanmoy: todo eso tiene sentido, excepto por el hecho de que si agrego una segunda escritura después de la primera, obtengo el error que espero, y como se describe en la página del manual. Si lo que estás describiendo fuera la historia completa, no habría diferencia entre la primera y la segunda escritura (). Usted dice que debería llamar a close() antes de write() para ver el error en el servidor, pero no puedo ver cómo se supone que debo saber cuándo hacerlo si no es a través de una escritura fallida().

    – freír regular

    12 de julio de 2012 a las 8:29

  • @regularfry Es probable que el kernel tenga un tiempo de espera sobre cuánto tiempo espera que el otro lado se apague. Después de ese tiempo de espera, comenzará a enviar respuestas de “reinicio de conexión” que luego harán que la escritura falle. Es decir, la primera escritura está bien, pero recibe una respuesta de restablecimiento de la conexión, por eso falla la segunda escritura.

    – Por Johansson

    12 de julio de 2012 a las 14:58

  • Realmente deberías cambiar eso close antes de write para shutdown o algo. Como dijo Per Johansson, el código tal como está escrito es incorrecto para mostrar el problema (solo está dando EBADF) y podría ser peligroso en un programa de subprocesos múltiples.

    – R.. GitHub DEJA DE AYUDAR A ICE

    18 de julio de 2012 a las 14:35

Después de haber llamado write() una (primera) vez (como se codifica en su ejemplo) después del cliente close()ed el socket, obtendrá el esperado EPIPE y SIGPIPE en cualquier llamada sucesiva a write().

Simplemente intente agregar otra escritura () para provocar el error:

...
printf( "Errno before: %s\n", strerror( errno ) );
printf( "Write result: %d\n", write( client_fd, "123", 3 ) );
printf( "Errno after:  %s\n", strerror( errno ) );

printf( "Errno before: %s\n", strerror( errno ) );
printf( "Write result: %d\n", write( client_fd, "A", 1 ) );
printf( "Errno after:  %s\n", strerror( errno ) );
...

La salida será:

Accepting
Server sleeping
Client closing its fd... Client exiting.
Errno before: Success
Write result: 3
Errno after:  Success
Errno before: Success
Client status is 0, server status is 13

La salida de los dos últimos printf()s falta ya que el proceso termina debido a SIGPIPE siendo planteada por la segunda llamada a write(). Para evitar la finalización del proceso, es posible que desee hacer que el proceso ignore SIGPIPE.

  • Si. ¿Por qué es esto necesario? ¿Cómo puedo obtener el error en la primera escritura? El protocolo con el que estoy tratando realmente no tiene espacio para datos falsos, y el lado del servidor deberían tener suficiente información para hacer que la primera escritura falle. Además, el solo uso de una segunda escritura simplemente hace retroceder el problema: ¿qué sucede cuando el cliente se desconecta entre la primera y la segunda escritura?

    – freír regular

    12 de julio de 2012 a las 11:57

  • @regularfry, ¿Puedes por favor? vea si puede agregar las siguientes líneas de código antes de escribir, int tcp_info_length; estructura tcp_info tcp_info; tcp_info_length = sizeof(tcp_info) ;getsockopt(client_fd, SOL_TCP, TCP_INFO, (void *)&tcp_info, (sockl en_t *)&tcp_info_length ); El miembro tcp_info.tcpi_state tiene el estado TCP actual. Recibo el valor 8(CLOSE_WAIT) a 7(TCP_CLOSE) antes/después de la primera escritura respectivamente. ¿Puede usar esta información para manejar este caso? pl. consulte el archivo de encabezado tcp.h en la carpeta netinet para ver todos los valores de los estados de TCP.

    – Tanmoy Bandyopadhyay

    13 de julio de 2012 a las 8:40


  • Eso coincide con lo que veo. Sin embargo, parece extraño que sea necesario hacer un getsockopt en cada escritura solo para asegurarse de que el socket no estaba cerrado.

    – freír regular

    13 de julio de 2012 a las 10:00

Sospecho que lo que está sucediendo es que el socket del lado del servidor aún es válido, por lo que su llamada de escritura está haciendo un intento válido de escribir en su descriptor de archivo a pesar de que su sesión TCP está en un estado cerrado. Si estoy completamente equivocado, házmelo saber.

Supongo que te estás topando con la pila TCP detectando un envío fallido e intentando retransmitir. Realice llamadas posteriores a write() fallar en silencio? En otras palabras, intente escribir cinco veces en el socket cerrado y vea si finalmente obtiene un SIGPIPE. Y cuando dice que la escritura ‘tiene éxito’, ¿obtiene un resultado de retorno de 3?

  • No, si agrego una segunda lectura, esa falla como se esperaba. Y sí, obtengo un valor de retorno de 3 desde el primero.

    – freír regular

    12 de julio de 2012 a las 8:18

  • No, si agrego una segunda lectura, esa falla como se esperaba. Y sí, obtengo un valor de retorno de 3 desde el primero.

    – freír regular

    12 de julio de 2012 a las 8:18

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad