home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Perl CookbookPerl CookbookSearch this book

17.2. Writing a TCP Server

17.2.2. Solution

This recipe assumes you're using the Internet to communicate. For TCP-like communication within a single Unix machine, see Recipe 17.6.

Use the standard IO::Socket::INET class:

use IO::Socket;

$server = IO::Socket::INET->new(LocalPort => $server_port,
                                Type      => SOCK_STREAM,
                                Reuse     => 1,
                                Listen    => 10 )   # or SOMAXCONN
    or die "Couldn't be a tcp server on port $server_port : $@\n";

while ($client = $server->accept( )) {
    # $client is the new connection
}

close($server);

Or craft it by hand for better control:

use Socket;

# make the socket
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));

# so we can restart our server quickly
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);

# build up my socket address
$my_addr = sockaddr_in($server_port, INADDR_ANY);
bind(SERVER, $my_addr)
    or die "Couldn't bind to port $server_port : $!\n";

# establish a queue for incoming connections
listen(SERVER, SOMAXCONN)
    or die "Couldn't listen on port $server_port : $!\n";

# accept and process connections
while (accept(CLIENT, SERVER)) {
    # do something with CLIENT
}

close(SERVER);

17.2.3. Discussion

Setting up a server is more complicated than being a client. The optional listen function tells the operating system how many pending, unanswered connections can queue up while waiting for your server. The setsockopt function used in the Solution allows you to avoid waiting two minutes after killing your server before you restart it again (valuable in testing). The bind call registers your server with the kernel so others can find you. Finally, accept takes the incoming connections one by one.

The numeric argument to listen is the number of unaccept ed connections that the operating system should queue before clients start getting "connection refused" errors. Historically, the maximum listen value was 5, and even today, many operating systems silently limit this queue size to around 20. With busy web servers becoming commonplace, many vendors have increased this value. Your documented system maximum can be found in the SOMAXCONN constant from the Socket module.

The accept function takes two arguments: the filehandle to connect to the remote client and the server filehandle. It returns the client's port and IP address, as packed by inet_ntoa:

use Socket;

while ($client_address = accept(CLIENT, SERVER)) {
    ($port, $packed_ip) = sockaddr_in($client_address);
    $dotted_quad = inet_ntoa($packed_ip);
    # do as thou wilt
}

With the IO::Socket classes, accept is a method of the server filehandle:

while ($client = $server->accept( )) {
    # ...
}

If you call the accept method in list context, it returns the client socket and its address:

while (($client,$client_address) = $server->accept( )) {
    # ...
}

If no connection is waiting, your program blocks in the accept until a connection comes in. If you want to ensure that your accept won't block, use non-blocking sockets:

use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);

$flags = fcntl(SERVER, F_GETFL, 0)
            or die "Can't get flags for the socket: $!\n";

$flags = fcntl(SERVER, F_SETFL, $flags | O_NONBLOCK)
            or die "Can't set flags for the socket: $!\n";

Now when you accept and nothing is waiting for you, accept will return undef and set $! to EWOULDBLOCK.

You might fear that when the return flags from F_GETFL are 0, this would trigger the die just as a failure from undef would. Not so—as with ioctl, a non-error return from fcntl is mapped by Perl to the special value "0 but true". This special string is even exempt from non-numeric warnings, so feel free to use it in your functions when you want to return a value that's numerically zero yet still true. It probably should have been "0 and sneaky" instead.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.