davies has asked for the wisdom of the Perl Monks concerning the following question:

I have a client/server pair of scripts that work fine. There is a minor issue on Linux that I want to solve. After running the client from a Windows box, all works as expected, but if the client is run twice in quick succession on Linux, the second attempt results in a message on the client that the server is not responding. netstat reveals that there is still a socket open on the client, although there is a specific close $socket in both the server and client. I have tried restricting this to the client only and have tried both $socket->close and $socket->shutdown(2). I have found a SO_LINGER option with little documentation and have tried setting that to zero. The time on Linux for the socket to reset seems to be of the order of a minute. What should I try next, please? The client code follows; the server code is not very different & can be posted if desired.

use strict; use warnings; use IO::Socket; use sigtrap qw/handler signal_handler normal-signals/; use constant SERVER => 'dns'; use constant PORT => 31416; my $EOL = "\015\012"; my $SENTINEL = '.' . $EOL; die 'Which machine do you want to wake?' unless scalar @ARGV; my $socket = IO::Socket::INET->new( Proto => 'tcp', # protocol PeerAddr => SERVER, # Address or name of server PeerPort => PORT, # port of server ) or die "Server <" . SERVER . "> not responding: <$!>"; $socket->autoflush(1); # Send immediately $socket->setsockopt( SOL_SOCKET, SO_LINGER, 0 ); while (@ARGV) { print $socket (shift @ARGV) . $EOL; # Send to Server while (my $res = <$socket>) { # Receive result from server last if ($res eq $SENTINEL); # Close if sentinel received print $res; # Print the result } } $socket->shutdown(2) or warn $!; sub signal_handler { close $socket or warn $!; }

Regards,

John Davies

Update: The socket is in TIME_WAIT state on the client. No socket appears on the server. The server does not fork, simply sending an etherwake packet to the MAC of any machine(s) named in the args & looping until it responds to ping or reaches a timeout I have set. I see that Reuse is now deprecated and have changed the code to reuse both the addr and the port, both on the server and the client. The only change this makes to the behaviour is that, previously, the port was in TIME_WAIT until a minute had passed or another connection request was made and refused. Now, when the connection is refused, the port remains in TIME_WAIT. A further connection attempt, as previously, still succeeds, but the result is that there can now be multiple copies of the port in TIME_WAIT state. Also, the connection is refused for at least a much longer time than the minute experienced previously. I think I preferred the previous version. :-) My reading (thanks for all the references) leads me to the conclusion that this is the intended behaviour and that I should live with it. I'd rather not, if possible. Experimenting with multiple clients leads me to conclude that this IS a server side problem, as the symptoms move from client to client.

Replies are listed 'Best First'.
Re: IO::Socket persisting on Linux despite being closed
by trippledubs (Deacon) on Oct 25, 2018 at 19:15 UTC
    Problem might be on the Server, error message makes me think it is, but this may benefit there as well, setting ReuseAddr to 1.
    my $socket = IO::Socket::INET->new( ReuseAddr => 1,

    Socket options are documented in socket;7 man 7 socket

    Your server could be blocking on a <$fh> call if that doesn't work.

Re: IO::Socket persisting on Linux despite being closed
by superfrink (Curate) on Oct 25, 2018 at 19:12 UTC

    Linux keeps the socket in use while it is in the TIME_WAIT state. The SO_REUSEADDR option may help.

    I haven't tried but does the following work?

    $socket->setsockopt( SOL_SOCKET, SO_REUSEADDR, 1 );

    Update: IO::Socket::INET references SO_REUSEADDR and SO_REUSEPORT. You may need to try each.

      SO_REUSEPORT is Linux-specific option to facilitate multi-threaded servers:
      SO_REUSEPORT (since Linux 3.9)
      Permits multiple AF_INET or AF_INET6 sockets to be bound to an identical socket address.
      For TCP sockets, this option allows accept(2) load distribution in a multi-threaded server to be improved by using a distinct listener socket for each thread. This provides improved load distribution as compared to traditional techniques such using a single accept(2)ing thread that distributes connections, or having multiple threads that compete to accept(2) from the same socket.
      Probably shouldn't be relevant here.
Re: IO::Socket persisting on Linux despite being closed
by StuLong (Acolyte) on Oct 25, 2018 at 20:25 UTC
    Just out of curiosity, is the server listening on a port and forking off when a connection is made? Sockets will hang around a short while in TIME_WAIT state after being cleanly closed. If your server is not running fork to give the connected client its own process (and thus, its own separate port), then when the connection ends the server port may be unresponsive for a short period. Forking the server for each connection means that the random port given to the fork will be the one going into TIME_WAIT when the connection drops, not the server listening port.
Re: IO::Socket persisting on Linux despite being closed (updated)
by localshop (Monk) on Oct 27, 2018 at 20:25 UTC

    It's been a while since I've done much work at this layer but it looks as though you are running a single threaded server listener and so you must wait for the TIMEOUT release by the server. This is an important necessary requirement - you do not want another client to connect to your TCP connection and you do not want to lose the connection if it is interrupted for a minute. I may not be explaining this very well but is worth reading more on single and multi-threaded TCP servers.

    A good place to start off the top of my search is this SO article. or some of the older PM nodes such as 549414

Re: IO::Socket persisting on Linux despite being closed
by Anonymous Monk on Oct 25, 2018 at 19:39 UTC

    netstat reveals that there is still a socket open on the client
    Which state is it in? Note that TCP requires participation of both parties to close a connection (see also: TCP TARPIT), so even if a socket-owning process died, the kernel still has to maintain some state about the recently passed connection.

    the second attempt results in a message on the client that the server is not responding
    This sounds more like a server bug, what does netstat say there? Capturing the exchanges (both successful and unsuccessful) with Wireshark might prove enlightening.

Re: IO::Socket persisting on Linux despite being closed (updated)
by Anonymous Monk on Oct 26, 2018 at 19:24 UTC
Re: IO::Socket persisting on Linux despite being closed (updated: HTTP::Server::Simple)
by Anonymous Monk on Oct 26, 2018 at 12:06 UTC