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 theAnyEvent
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
Receiving Multicast on a Server with Multiple Interfaces (Linux)
Crontab - Simple Echo Not Running
Where to Put Svn Repository Directory in Linux
Check If All Lines from One File Are Present Somewhere in Another File
How to Programmatically Pick and Choose Which Core of a Multi-Core CPU My Thread Should Run On
Scsi Read (10) and Write (10) with The Scsi Generic Interface
Debugging Ld, "Inconsistency Detected by Ld.So"
How to Use Gpg Signing Key on a Remote Server
What Is The Size of Coap Packet
How to Create a Multi Partition Sd Disk Image Without Root Privileges
How to Make Sure Only One Instance of a Bash Script Is Running at a Time
Automatically Sync Two Amazon S3 Buckets, Besides S3Cmd