Often times when writing a server you will need to be able to handle multiple client connections at a time. To do this you will want to create a threaded server.

The first thing that you will need to do is open a listening socket and create a loop that will continue listening for new clients. In this example I use IO::Socket::INET and a simple while(1) loop. We also need to create an array for our threads as shown in my Perl threading tutorial.

sub Main { # flush after every write $| = 1; my ( $socket, $client_socket ); # Bind to listening address and port $socket = new IO::Socket::INET ( LocalHost => '127.0.0.1', LocalPort => '1337', Proto => 'tcp', Listen => 5, Reuse => 1 ) or die "Could not open socket: ".$!."

"; print "SERVER Waiting for client connections...

"; my @clients = (); while(1) { # Waiting for new client connection. $client_socket = $socket->accept(); # Push new client connection to it's own thread push ( @clients, threads->create( \&clientHandler, $client_socket ) ); foreach ( @clients ) { if( $_->is_joinable() ) { $_->join(); } } } $socket->close(); return 1; }

The code above will accept connections from new users, then throw the client connection into a thread where commands can be processed.

To process commands you will need to create the client handler function and a while loop to handle the buffer. Within the while loop commands can be processed by matching buffer against regular expression. You could create a regular expression to get command & arguments then use a case-switch, but I won’t cover this method.

sub clientHandler { # Socket is passed to thread as first (and only) argument. my ($client_socket) = @_; # Create hash for user connection/session information and set initial connection information. my %user = (); $user{peer_address} = $client_socket->peerhost(); $user{peer_port} = $client_socket->peerport(); print "Accepted New Client Connection From:".$user{peer_address}.":".$user{peer_port}."

"; # Let client know that server is ready for commands. print $client_socket "> "; # Listen for commands while client socket remains open while( my $buffer = <$client_socket> ) { # Accept the command `HELLO` from client with optional arguments if( $buffer =~ /^HELLO(\s|$)/i ) { #Example reply print $client_socket "HELLO THERE!!

"; print $client_socket "Your IP:\t".$user{peer_address}."

"; print $client_socket "Your Port:\t".$user{peer_port}."

"; } # This will terminate the client connection to the server if( $buffer =~ /^QUIT(\s|$)/i ) { # Print to client, and print to STDOUT then exit client connection & thread print $client_socket "GOODBYE

"; print "Client exit from ".$user{peer_address}.":".$user{peer_port}."

"; $client_socket->shutdown(2); threads->exit(); } print $client_socket "> "; } print "Client exit from ".$user{peer_address}.":".$user{peer_port}."

"; # Client has exited so thread should exit too threads->exit(); }

In the example above you will notice the command 1 quit allows the client to exit the server cleanly. This allows the server to issue the 1 $client_socket->shutdown() method which is a clean way of exiting a socket. Then it calls 1 threads-exit() which is how you cleanly exit a thread. By exiting this way the server won’t be keeping open potentially stale connections. It is also wise to add some sort of PING-PONG between the client and server to check that connections are still alive and active.

$ perl PerlServer.pl SERVER Waiting for client connections... Accepted New Client Connection From:127.0.0.1:52562 Client exit from 127.0.0.1:52562

$ telnet localhost 1337 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. > HELLO HELLO THERE!! Your IP: 127.0.0.1 Your Port: 63600 > QUIT GOODBYE Connection closed by foreign host.

Here is the full code for the example server

#!/usr/bin/perl use strict; use warnings; use IO::Socket::INET; use threads; sub Main { # flush after every write $| = 1; my ( $socket, $client_socket ); # Bind to listening address and port $socket = new IO::Socket::INET ( LocalHost => '127.0.0.1', LocalPort => '1337', Proto => 'tcp', Listen => 5, Reuse => 1 ) or die "Could not open socket: ".$!."

"; print "SERVER Waiting for client connections...

"; my @clients = (); while(1) { # Waiting for new client connection. $client_socket = $socket->accept(); # Push new client connection to it's own thread push ( @clients, threads->create( \&clientHandler, $client_socket ) ); foreach ( @clients ) { if( $_->is_joinable() ) { $_->join(); } } } $socket->close(); return 1; } sub clientHandler { # Socket is passed to thread as first (and only) argument. my ($client_socket) = @_; # Create hash for user connection/session information and set initial connection information. my %user = (); $user{peer_address} = $client_socket->peerhost(); $user{peer_port} = $client_socket->peerport(); print "Accepted New Client Connection From:".$user{peer_address}.":".$user{peer_port}."

"; # Let client know that server is ready for commands. print $client_socket "> "; # Listen for commands while client socket remains open while( my $buffer = <$client_socket> ) { # Accept the command `HELLO` from client with optional arguments if( $buffer =~ /^HELLO(\s|$)/i ) { #Example reply print $client_socket "HELLO THERE!!

"; print $client_socket "Your IP:\t".$user{peer_address}."

"; print $client_socket "Your Port:\t".$user{peer_port}."

"; } # This will terminate the client connection to the server if( $buffer =~ /^QUIT(\s|$)/i ) { # Print to client, and print to STDOUT then exit client connection & thread print $client_socket "GOODBYE

"; print "Client exit from ".$user{peer_address}.":".$user{peer_port}."

"; $client_socket->shutdown(2); threads->exit(); } print $client_socket "> "; } print "Client exit from ".$user{peer_address}.":".$user{peer_port}."

"; # Client has exited so thread should exit too threads->exit(); } # Start the Main loop Main();

I hope this helped, sorry about the lack of indentation in some of the code, for some reason WordPress is messing it up in my code blocks.