Perl not closing TCP sockets if clients are no longer connected?

The purpose of the application is to listen to a specific UDP multicast, and then forward the data to any TCP clients connected to the server. The code works fine, but I have a problem with sockets that do not close after disconnecting TCP clients. The socketsniffer utility shows that sockets remain open and all UDP data continues to be redirected to clients. I believe the problem is with the if ($ write-> connected ()) block, as it always returns true, even if the TCP client is no longer connected. I use standard Windows Telnet to connect to the server and view data. When I close telnet, the TCP socket is supposed to close on the server.

Any reason why connected () shows connections are active, even if they are not? Also, what alternative should I use?

the code:

#!/usr/bin/perl use IO::Socket::Multicast; use IO::Socket; use IO::Select; my $tcp_port = "4550"; my $tcp_socket = IO::Socket::INET->new( Listen => SOMAXCONN, LocalAddr => '0.0.0.0', LocalPort => $tcp_port, Proto => 'tcp', ReuseAddr => 1, ); use Socket qw(IPPROTO_TCP TCP_NODELAY); setsockopt( $tcp_socket, IPPROTO_TCP, TCP_NODELAY, 1); use constant GROUP => '239.2.0.81'; use constant PORT => '6550'; my $udp_socket= IO::Socket::Multicast->new(Proto=>'udp',LocalPort=>PORT); $udp_socket->mcast_add(GROUP) || die "Couldn't set group: $!\n"; my $read_select = IO::Select->new(); my $write_select = IO::Select->new(); $read_select->add($tcp_socket); $read_select->add($udp_socket); ## Loop forever, reading data from the UDP socket and writing it to the ## TCP socket(s). while (1) { ## No timeout specified (see docs for IO::Select). This will block until a TCP ## client connects or we have data. my @read = $read_select->can_read(); foreach my $read (@read) { if ($read == $tcp_socket) { ## Handle connect from TCP client. Note that UDP connections are ## stateless (no accept necessary)... my $new_tcp = $read->accept(); $write_select->add($new_tcp); } elsif ($read == $udp_socket) { ## Handle data received from UDP socket... my $recv_buffer; $udp_socket->recv($recv_buffer, 1024, undef); ## Write the data read from UDP out to the TCP client(s). Again, no ## timeout. This will block until a TCP socket is writable. my @write = $write_select->can_write(); foreach my $write (@write) { ## Make sure the socket is still connected before writing. if ($write->connected()) { $write->send($recv_buffer); } else { $write_select->remove($write); close $write; } } } } } 
+4
source share
4 answers

I don’t know anything about perl or perl sockets, but I can’t come up with a socket API that makes it possible to know if a socket is connected. In fact, I'm pretty sure that TCP doesn't really know how this happens. This tells me that bound () is not telling you what you think is telling you. (I have no idea, but I bet it tells you whether you are calling / accepting or not)

Usually sockets tell you that they disconnected by reading or writing zero bytes - you can check the return value of the record to see if it ever returns zero

+5
source

Thanks for the feedback. I found a solution that seems to work well for me (thanks Stuart). It was as simple as checking the return value:

 $resultsend = $write->send($recv_buffer); if (!$resultsend) { $write_select->remove($write); close $write; } 

TCP sockets now close after disconnecting the client.

+2
source

The IO :: Socket connected method just tells you if the socket is in a connected state, i.e. did you call "connect" on it after it was created. As Stuart said, there is no general way to find out if the other end of the TCP socket has fallen and is still connected.

+1
source

From the top of my head try:

ReuseAddr => 0

I am more than sure that the magic of IO :: Socket is causing problems.

0
source

Source: https://habr.com/ru/post/1308276/


All Articles