开发者

How to detect a TCP socket disconnection (with C Berkeley socket)

开发者 https://www.devze.com 2023-03-13 20:09 出处:网络
I am using a loop to read message out from a c Berkeley socket but I am not able to detect when the socket is disconnected so I would accept a new connection. please help

I am using a loop to read message out from a c Berkeley socket but I am not able to detect when the socket is disconnected so I would accept a new connection. please help

while(true) {
            bzero(buffer,256);
            n = read(newsockfd,buffer,255);
            printf("%s\n",buffer开发者_StackOverflow);        
}


The only way you can detect that a socket is connected is by writing to it.

Getting a error on read()/recv() will indicate that the connection is broken, but not getting an error when reading doesn't mean that the connection is up.

You may be interested in reading this: http://lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html

In addition, using TCP Keep Alive may help distinguish between inactive and broken connections (by sending something at regular intervals even if there's no data to be sent by the application).

(EDIT: Removed incorrect sentence as pointed out by @Damon, thanks.)


Your problem is that you are completely ignoring the result returned by read(). Your code after read() should look at least like this:

if (n == 0) // peer disconnected
    break;
else if (n == -1) // error
{
    perror("read");
    break;
}
else // received 'n' bytes
{
    printf("%.*s", n, buffer);
}

And accepting a new connection should be done in a separate thread, not dependent on end of stream on this connection.

The bzero() call is pointless, just a workaround for prior errors.


That's because you didn't use keepalive timeout. In receiving side, keepalive socket option is the best solution for detecting dead connection.

But, in case of your application continue to write to socket, there is something to think more. Even though you already set keepalive option to your application socket, you can't detect in time the dead connection state of the socket, in case of your app keeps writing on the socket. That's because of tcp retransmission by the kernel tcp stack. tcp_retries1 and tcp_retries2 are kernel parameters for configuring tcp retransmission timeout. It's hard to predict precise time of retransmission timeout because it's calculated by RTT mechanism. You can see this computation in rfc793. (3.7. Data Communication)

https://www.rfc-editor.org/rfc/rfc793.txt

Each platforms have kernel configurations for tcp retransmission.

Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4)

http://linux.die.net/man/7/tcp

HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval

http://www.hpuxtips.es/?q=node/53

AIX : rto_low, rto_high, rto_length, rto_limit

http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf

You should set lower value for tcp_retries2 (default 15) if you want to early detect dead connection, but it's not precise time as I already said. In addition, currently you can't set those values only for single socket. Those are global kernel parameters. There was some trial to apply tcp retransmission socket option for single socket(http://patchwork.ozlabs.org/patch/55236/), but I don't think it was applied into kernel mainline. I can't find those options definition in system header files.

For reference, you can monitor your keepalive socket option through 'netstat --timers' like below. https://stackoverflow.com/questions/34914278

netstat -c --timer | grep "192.0.0.1:43245             192.0.68.1:49742"

tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (1.92/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (0.71/0/0)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (9.46/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (8.30/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (7.14/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (5.98/0/1)
tcp        0      0 192.0.0.1:43245             192.0.68.1:49742            ESTABLISHED keepalive (4.82/0/1)

In addition, when keepalive timeout ocurrs, you can meet different return events depending on platforms you use, so you must not decide dead connection status only by return events. For example, HP returns POLLERR event and AIX returns just POLLIN event when keepalive timeout occurs. You will meet ETIMEDOUT error in recv() call at that time.

In recent kernel version(since 2.6.37), you can use TCP_USER_TIMEOUT option will work well. This option can be used for single socket.

0

精彩评论

暂无评论...
验证码 换一张
取 消