Home » Classes » Fall 2003 » Networked Objects » Perl Server Info
Truly Interactive TV
Perl Server Info
December 19, 2003
 
Since I seem to be the only Networked Objects student to build a Perl TCP/IP server for their project (at least this year) Tom asked me to make sure I documented some pointers on how to do it. So, in the spirit of spreading the Perl gospel to the ITP community, here it is.

First of all, you're welcome to look at the Perl source code for this project, keeping in mind the caveat that 1. I tend to write extremely ideosyncratic code and 2. there are very few actual comments in the code. (The stuff that's commented out is a mix of false starts, future features, and incomplete ideas.) With that in mind, here are some of the key elements applicable to other projects:

  • The IO::Socket Module is really the key element in creating a Perl TCP server. It makes things (relatively) easy, since all you need is a simple declaration to get the server rolling:
    my $server = new IO::Socket::INET (
    	Proto     => 'tcp',
    	LocalPort => $socketnum,
    	Listen    => '1',
    	Reset	  => '1'
    );
    
    IO::Socket is installed on stage, but you can find it (with more detailed information) at CPAN.

    It's also probably worth reading the chapter on sockets in the Perl Cookbook. Especially considering that I was in a rush to get this project done quickly; I might have done things differently with more time to explore the intricacies of the module.

    With that in mind, here's what I did after declaring the new socket object.

  • First, make sure the socket opened properly:
    unless($server) {
    	die "Can't create server on port $socketnum\n";
    }
    
    I had lots of problems with the program dying at this point, especially when I shut down the server program unexpectedly and stage wouldn't open the port. I found out later that that the perl server was still running in the background on that port, which was easily resolved by:
    ps -ef | grep jgr225
    
    kill [appropriate pids]
    
    Problem solved, but still a good idea to Control-C the perl server rather than simply shutting down the terminal window.

  • The server's on, but not listening yet. So, make sure everything's clean ...
    $server->autoflush(1);
    
    ... then create a loop for the server to listen on that port ...
    my $handler;
    
    while ($handler = $server->accept()) {
    
    ... and accept the client when it says hello.
    	$handler or die "accept: $!\n";
    
    	my $peeraddr = $handler->peeraddr;
    	printf "accept %s\n\n", $handler->peerhost;
    
  • Once the client has been accepted, then we can start listening to what it has to say. Another loop:
    	while(defined ($line = <$handler>)){
    
    And play with $line to your heart's content.

  • When the client stops talking, bid it adieu...
    	}
    
    	print "Bye $alias!\n";
    }
    

    ... and wait for a new connection.

    In practice, this doesn't happen until a new client arrives. That is to say, it would be nice to say goodbye when the client is turned off, but in fact this doesn't happen until the client is switched off and on (and a new socket connection is initiated). This makes sense, sort of, because no communication is not a sign that the client has left. In fact, it could just be resting.

    Or perhaps, there's a simple solution I didn't consider. Which is entirely possible and in fact more than likely.

  • One bug I found in this original setup was that the server would crash whenever the client logged off, returning a "Broken pipe" error message. After a bit of digging, I found a workaround:
    $SIG{'PIPE'} = 'IGNORE';
    

    Popping this at the head of your script should keep things running once a client leaves.

  • Keep in mind that this server script is just for single client, not multi-threaded, communication. That is to say, you can't log in two clients on this server. That was a problem for me, since I was using this as a mediator between two modules.

    To solve this problem, you can do lots of things: fork the processes, use the select() command, create a buffered array of clients ... all of which were too complicated for me to explore given time constraints. So, in the Perl spirit ("there's more than one way to do it," remember?) I cheated a bit. I ran two servers in two different terminals, each listening to a different port. Each wrote their client's input to a shared file as soon as it was recieved, and read the shared file every second to stay-up-to-date with the conversation. So they indeed talked to each other -- just not within the same process. A somewhat inefficient hack, and not scaleable, but worked fine for my purposes.

  • That's about all I've learned about creating a basic Perl TCP server. Here are some more resources I've found on the web:
    » How to Write a Chat Server from Hotwired Webmonkey
    » TCP Clients with IO::Socket
    » Perl, Sockets and TCP/IP Networking

  • Copyright © 2003 James G. Robinson
    (and various collaborators, where noted).