Home > OS >  How to check if a client has disconnected?
How to check if a client has disconnected?

Time:05-02

I have a simple server socket

my $server = IO::Socket::INET->new(
    LocalPort => $config{'local-port'},
    Reuse     => 1,
    Listen    => 10,
    Timeout   => 1,
    Blocking  => 1
) or croak "Couln't start server: $!\n";

I want to keep doing some routine while client is connected

while (1) {
    my $client = $server->accept;
    next unless $client;
    say "new connection";
    # this loop never ends
    while ( $client->connected ) {
       # do_work();
    }
    say "connection closed";
}

But $socket->connected always return true (or seemingly until tcp keepalive is not sent).

Is there a way to check if client is still connected (for example if it didn't send anything in 10 seconds it can be considered disconnected)?

CodePudding user response:

Is there a way to check if client is still connected (for example if it didn't send anything in 10 seconds it can be considered disconnected)?

"Disconnected" in terms of TCP means that an explicit TCP shutdown was done. No data for 10 seconds is different from this - it is an expectation that the application will send data every 10 seconds and if this does not happen something is wrong, like crash of peer or loss of connectivity.

To detect any of this it is necessary to actually attempt to read from the socket. In case of an explicit TCP disconnect the read will return that 0 bytes are read w/o any failure.

This is different from having the connection open but no data available - here the read will hang on a blocking socket so select or similar should be used to check first if there would be something to read. Alternatively use a non-blocking socket in which case the read would fail with EWOULDBLOCK (or EAGAIN, which is the same on most OS).

If actually reading the data does not fit in the way the program is designed, one could instead also use a combination of select (check that something is read) and MSG_PEEK to just check the state of the socket buffer and the underlying connection, i.e. something like this:

 vec(my $rin = '', fileno($socket), 1) = 1;
 my $n = select($rin, undef, undef, undef, 0);
 if ($n<0) {
      # something wrong, socket likely already explicitly locally closed
 } elsif ($n == 0) {
      # read would block, i.e. no explicit disconnect and no data to read
 } else {
      $n = recv($socket, my $buf, 1, MSG_PEEK);
      if ($n>0) {
            # data available in socket buffer
      } elsif ($n==0) {
            # no data available and no errno -> socket closed by peer
      } else {
            # socket broken, for example keep alive timer failed
      }
 }
  • Related