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

Hello

Could someone offer some advice on the code below? When I connect a client it connects and does as I would expect. However, it seems to close the socket after the first input from the client.

Is there any way to keep the server running to keep sending/receiving data to/from the client, until the client disconnects?

Ideally I'd like the client to connect, send a 99 and get a corresponding response from the server. Then, the client stays connected and at some point in the future is might send a 63 string or maybe even another 99. All of this without the server closing the connection and forcing the client to reconnect

Thanks!

#!/usr/bin/perl use strict; use warnings; use feature 'say'; use IO::Socket qw(AF_INET AF_UNIX SOCK_STREAM SHUT_WR); use Data::Dumper; my $server = IO::Socket->new( Domain => AF_INET, Type => SOCK_STREAM, Proto => 'tcp', LocalHost => '0.0.0.0', LocalPort => 3333, ReusePort => 1, Listen => 5, ) || die "Can't open socket: $IO::Socket::errstr"; say "Waiting on 3333"; while (1) { my $client = $server->accept(); my $client_address = $client->peerhost(); my $client_port = $client->peerport(); say "Connection from $client_address:$client_port"; my $data; $client->recv($data, 1024); say "received data: $data"; if ($data =~ m/99/) { $data = "We've received a string starting withh 99"; } if ($data =~ m/63/) { $data = "We've received a string starting with 63"; } $client->send($data); }

Replies are listed 'Best First'.
Re: IO::Socket simple server
by haukex (Archbishop) on May 29, 2023 at 16:38 UTC

    If you want to keep waiting on data from the client, you need to keep reading from the client. See for example "TCP Servers with IO::Socket" in perlipc.

    However, I would strongly recommend against writing a server at such a low level. Nowadays, I think that event loops are the way to go. I've used POE, but that has a fairly high learning curve, and so I can recommend Mojo::IOLoop. Yes Mojolicious is a web framework, but the aforementioned module can be used independently of the framework to write TCP servers IMHO very easily. Example code here.

Re: IO::Socket simple server
by tybalt89 (Monsignor) on May 29, 2023 at 18:31 UTC

    The questions I have are: After a client disconnects, do you want to do another accept? (seems like yes), and Do you want to have simultaneous conversations with multiple clients? (seems like no).

    Otherwise, just some simple tweaks...

    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11152468 use warnings; $SIG{__WARN__} = sub { die $@ }; use feature 'say'; use IO::Socket qw(AF_INET AF_UNIX SOCK_STREAM SHUT_WR); use Data::Dumper; my $server = IO::Socket::INET->new( LocalPort => 3333, ReusePort => 1, Listen => 5, ) or die "Can't open socket: $IO::Socket::errstr"; while (1) { say "Waiting on 3333"; my $client = $server->accept() or die "accept failed on $!"; my $client_address = $client->peerhost(); my $client_port = $client->peerport(); say "Connection from $client_address:$client_port"; while( defined $client->recv(my $data, 1024) ) { say "received data: $data"; length $data or last; if ($data =~ m/99/) { $data = "We've received a string starting with 99\n"; } if ($data =~ m/63/) { $data = "We've received a string starting with 63\n"; } $client->send($data); } }
Re: IO::Socket simple server
by eyepopslikeamosquito (Archbishop) on May 29, 2023 at 22:14 UTC
Re: IO::Socket simple server
by Anonymous Monk on Jun 01, 2023 at 00:00 UTC

    Well you have other good answers by my 2 cents is this: You are reinventing he wheel making a socket server, and there is a lot of complication because you have to handle different client instances, and handle the various situations to manage the sockets/sessions/clients. Then you also have the problem of framing/structuring the info over the tcp stream itself. You are much better just jumping straight to something already event driven and using a higher level protocol so sockets, connections, tcp, are all abstracted away.

    An example is a simple HTTP server:

    use AnyEvent; use AnyEvent::HTTPD; # Create server my $server = AnyEvent::HTTPD->new(host => '127.0.0.1',port => 3333); # Setup response for requests $server->reg_cb ('/test' => sub { my ($obj, $req) = @_; print "Got message '".$req->content."' from client ".$req->client_ +host.":".$req->client_port."\n"; $req->respond([200, 'ok', { 'Content-Type' => 'text/plain' }, 'Hel +lo' ]); }); AnyEvent->condvar->recv; #wait forever

    For the client use LWP::UserAgent, or even AnyEvent::HTTP client:

    use AnyEvent; use AnyEvent::HTTP; my $cv = AnyEvent->condvar; http_post "http://127.0.0.1:3333/test", "99", persistent=>1, sub { my ($data, $headers) = @_; print "Got back message '$data' from server\n"; $cv->send; # stop waiting }; $cv->recv; # Wait for response