How to Accept Multiple Tcp Connections in Perl

How can I accept multiple TCP connections in Perl?

It's not threaded, but I think this does what I think you want:

#!/usr/bin/perl

use strict;
use warnings;

use IO::Socket;
use IO::Select;

my $tcp_port = "10008";
my $udp_port = "2099";

my $tcp_socket = IO::Socket::INET->new(
Listen => SOMAXCONN,
LocalAddr => 'localhost',
LocalPort => $tcp_port,
Proto => 'tcp',
ReuseAddr => 1,
);

my $udp_socket = IO::Socket::INET->new(
LocalAddr => 'localhost',
LocalPort => $udp_port,
Proto => 'udp',
);

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). Might want to install some kind of signal handler to
## ensure a clean shutdown.
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. What
## happens if no TCP clients are connected? Will IO::Select throw some
## kind of error trying to select on an empty set of sockets, or will the
## data read from UDP just get dropped on the floor?
my @write = $write_select->can_write();

foreach my $write (@write) {

## Make sure the socket is still connected before writing. Do we also
## need a SIGPIPE handler somewhere?
if ($write->connected()) {
$write->send($recv_buffer);
}
else {
$write_select->remove($write);
}

}

}

}

}

Disclaimer: I just banged that out. I imagine it's very fragile. Don't try and use that in a production environment without much testing and bulletproofing. It might eat your data. It might try and eat your lunch. Use at your own risk. No warranty.

Perl TCP Server handling multiple Client connections

Either fork, thread or do I/O multiplexing with select. Take a look at Net::Server and AnyEvent::Socket, too. For an example of I/O multiplexing, take a look at How can I accept multiple TCP connections in Perl?.

TCP Server using perl fork to accept multiple requests

You need to loop around the recv call to read more than one package from the client. Also, as it's currently written, the SIGCHLD signal interrupts accept so when the first child process dies, your server program terminates. You could just add a loop around the accept loop to restart the accept call.

Example:

#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket::INET;

$SIG{CHLD} = sub { wait; };

my $socket = new IO::Socket::INET (
LocalHost => '0.0.0.0',
LocalPort => '5000',
Proto => 'tcp',
Listen => 5,
Reuse => 1);
die "cannot create socket $!n" unless $socket;

sub child {
my $sock = shift;
my $data;
print "$$ connected\n";
# loop for as long as there's something coming in
while($sock->recv($data, 500) || $data) {
print "$$ $data"; # prepend the data with the process id
}
print "$$ disconnected\n";
exit 0;
}

while(1) {
while (my $new_sock = $socket->accept()) {
my $pid = fork();
die "Cannot fork: $!" unless defined($pid);

if ($pid == 0) { # This is the fork child
child($new_sock);
}
}
print "accept interrupted - restarting\n";
}

TCP Server with multiple connections in PERL based on specific code

There are two key ways of handling multiple sockets.

The first is - making use of IO::Select - which has a can_read function - this allows you to test whether a socket has data to read, and you can just iterate your socket list. Read the doc on IO::Select, as it has an example of how to do exactly what you're wanting.

The other approach is parallel processing. Specifically using either threading or forking to handle the $client_socket asynchronously. I'll refer you to: Perl daemonize with child daemons (mostly because rewriting parallel code is a bit more convoluted, and so perhaps out of scope). I'd suggest you probably want a 'forking' approach, as that's generally better suited to the style of parallelism.

How can I listen on multiple sockets in Perl?

Use the IO::Select module. perldoc IO::Select includes an example.

Here's a client example. Not guarneteed to be typo free or even work right:


use IO::Select;
use IO::Socket;
# also look at IO::Handle, which IO::Select inherits from

$lsn1 = IO::Socket::INET->new(PeerAddr=>'example.org', PeerPort=>8000, Proto=>'tcp');
$lsn2 = IO::Socket::INET->new(PeerAddr=>'example.org', PeerPort=>8001, Proto=>'tcp');
$lsn3 = IO::Socket::INET->new(PeerAddr=>'example.org', PeerPort=>8002, Proto=>'tcp');
$sel = IO::Select->new;
$sel->add($lsn1);
$sel->add($lsn2);
# don't add the third socket to the select if you are never going to read form it.

while(@ready = $sel->can_read) {
foreach $fh (@ready) {
#read your data
my $line = $fh->getline();
# do something with $line
#print the results on a third socket
$lsn3->print("blahblahblah");
}
}

this was too big to put in a comment field

You need to better define what you want to do. You have stated that you need to read from port A and write to port B. This is what the above code does. It waits for data to come in on the sockets $lsn1 and $lsn2 (ports 8000 and 8001), reads a line, then writes something back out to example.com on port 8002 (socket $lsn3).

Note that select is really only necessary if you need to read from multiple sockets. If you strictly need to read from only one socket, then scrap the IO::Select object and the while loop and just do $line = < $lsn1 > . That will block until a line is received.

Anyway, by your definition, the above code is a client. The code does actively connect to the server (example.org in this case). I suggest you read up on how IO::Socket::INET works. The parameters control whether it's a listening socket or not.

perl poe tcp server handle multiple clients

In ClientConnected callback, $kernel->alias_set('Downloader'); statement applies to very first connecting client(session), subsequent clients(sessions) should not set with same alias 'Downloader'. In 'StartSending' callback of InsliStates, post destination is 'Downloader' so that server sends data to very first connecting client. To send data to multiple clients use SESSION_ID as destination instead-of ALIAS in this case 'Downloader'. So replace:

$kernel->post('Downloader', 'OnSending');

by

$kernel->post($_[SESSION]->ID=>'OnSending');

in "StartSending" callback of Inlinestates. So it works fine now.

How do you send multiple files over a TCP connection with Perl?

Send a header with the length of the first file. Since they're text files, and this is Perl, it might be better to use the number of lines in the file. On the other side, read that number of lines in as the first file, then all of the rest as the second. This principle can be extended for any number of files.

Edit: You'll also want to translate the windows line endings to linux ones. A simple s/\r\n/\n/; should do the trick.

Is there a way to allow multiple connections to Dancer2

Perl programs are generally single-threaded. If you want to handle multiple things at the same time, you need to manage that explicitly.

  • You can run multiple instances of your Dancer app. When one instance is busy, the other instances can still handle requests. Some servers automatically support such “pre-forking”, for example Starman. This is the classic solution to your problem, coupled with the observation that your backend shouldn't do lots of stuff that block execution.

  • You can explicitly write your app to work asynchronously. Your sleep invocation is blocking the entire process, but you could also use libraries that let you resume handling of a request when some event occurs. For example, the Dancer2 docs show examples for using the AnyEvent timers.

If you are familiar with the Express web framework in JavaScript, it generally uses the second approach: NodeJS doesn't let you block the process by sleeping, and instead requires you to use promises (async/await) or callbacks to explicitly account for asynchronous execution.

Perl forked socket server, stops accepting connections when a client disconnects

On POSIX.1-2001 compliant systems, simply setting $SIG{CHLD} = 'IGNORE' should solve the problem.



Related Topics



Leave a reply



Submit