TCP Servers with IO::Socket

- TCP Servers with IO::Socket

# TCP Servers with IO::Socket

As always, setting up a server is little bit more involved than running a client. The model is that the server creates a special kind of socket that does nothing but listen on a particular port for incoming connections. It does this by calling the `IO::Socket::INET->new()` method with slightly different arguments than the client did.

Proto

  This is which protocol to use. Like our clients, we'll still specify `"tcp"` here.

LocalPort

  We specify a local port in the `LocalPort` argument, which we didn't do for the client. This is service name or port number for which you want to be the server. (Under Unix, ports under 1024 are restricted to the superuser.) In our sample, we'll use port 9000, but you can use any port that's not currently in use on your system. If you try to use one already in used, you'll get an ``Address already in use'' message. Under Unix, the `netstat -a` command will show which services current have servers.

Listen

  The `Listen` parameter is set to the maximum number of pending connections we can accept until we turn away incoming clients. Think of it as a call-waiting queue for your telephone. The low-level Socket module has a special symbol for the system maximum, which is SOMAXCONN.

Reuse

  The `Reuse` parameter is needed so that we restart our server manually without waiting a few minutes to allow system buffers to clear out.

Once the generic server socket has been created using the parameters listed above, the server then waits for a new client to connect to it. The server blocks in the `accept` method, which eventually accepts a bidirectional connection from the remote client. (Make sure to autoflush this handle to circumvent buffering.)

To add to user-friendliness, our server prompts the user for commands. Most servers don't do this. Because of the prompt without a newline, you'll have to use the `sysread` variant of the interactive client above.

This server accepts one of five different commands, sending output back to the client. Note that unlike most network servers, this one only handles one incoming client at a time. Multithreaded servers are covered in Chapter 6 of the Camel.

Here's the code. We'll

     #!/usr/bin/perl -w
     use IO::Socket;
     use Net::hostent;              # for OO version of gethostbyaddr

     $PORT = 9000;                  # pick something not in use

     $server = IO::Socket::INET->new( Proto     => 'tcp',
                                      LocalPort => $PORT,
                                      Listen    => SOMAXCONN,
                                      Reuse     => 1);

     die "can't setup server" unless $server;
     print "[Server $0 accepting clients]\n";

     while ($client = $server->accept()) {
       $client->autoflush(1);
       print $client "Welcome to $0; type help for command list.\n";
       $hostinfo = gethostbyaddr($client->peeraddr);
       printf "[Connect from %s]\n", $hostinfo ? $hostinfo->name : $client->peerhost;
       print $client "Command? ";
       while ( <$client>) {
         next unless /\S/;       # blank line
         if    (/quit|exit/i)    { last;                                     }
         elsif (/date|time/i)    { printf $client "%s\n", scalar localtime;  }
         elsif (/who/i )         { print  $client `who 2>&1`;                }
         elsif (/cookie/i )      { print  $client `/usr/games/fortune 2>&1`; }
         elsif (/motd/i )        { print  $client `cat /etc/motd 2>&1`;      }
         else {
           print $client "Commands: quit date who cookie motd\n";
         }
       } continue {
          print $client "Command? ";
       }
       close $client;
     }

- Back to Interactive Client with IO::Socket in the perlipc manpage

- Forward to UDP: Message Passing in the perlipc manpage

- Up to the perlipc manpage

TCP Servers with IO::Socket