start page | rating of books | rating of authors | reviews | copyrights

Perl Cookbook

Perl CookbookSearch this book
Previous: 17.13. Non-Forking Servers Chapter 17
Sockets
Next: 17.15. Making a Daemon Server
 

17.14. Writing a Multi-Homed Server

Problem

You want to write a server that knows that the machine it runs on has multiple IP addresses, and that it should possibly do different things for each address.

Solution

Don't bind your server to a particular address. Instead, bind to INADDR_ANY . Then, once you've accept ed a connection, use getsockname on the client socket to find out which address they connected to:

use Socket;  socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')); setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1); bind(SERVER, sockaddr_in($server_port, INADDR_ANY))     or die "Binding: $!\n";  # accept loop while (accept(CLIENT, SERVER)) {     $my_socket_address = getsockname(CLIENT);     ($port, $myaddr)   = sockaddr_in($my_socket_address); }

Discussion

Whereas getpeername (as discussed in Recipe 17.7 ) returns the address of the remote end of the socket, getsockname returns the address of the local end. When we've bound to INADDR_ANY , thus accepting connections on any address the machine has, we need to use getsockname to identify which address the client connected to.

If you're using IO::Socket::INET, your code will look like this:

$server = IO::Socket::INET->new(LocalPort => $server_port,                                 Type      => SOCK_STREAM,                                 Proto     => 'tcp',                                 Listen    => 10)     or die "Can't create server socket: $@\n";  while ($client = $server->accept()) {     $my_socket_address = $client->sockname();     ($port, $myaddr)   = sockaddr_in($my_socket_address);     # ... }

If you don't specify a local port to IO::Socket::INET->new , your socket will be bound to INADDR_ANY .

If you want your server to listen only for a particular virtual host, don't use INADDR_ANY . Instead, bind to a specific host address:

use Socket;  $port = 4269;                       # port to bind to $host = "specific.host.com";        # virtual host to listen on  socket(Server, PF_INET, SOCK_STREAM, getprotobyname("tcp"))     or die "socket: $!"; bind(Server, sockaddr_in($port, inet_aton($host)))     or die "bind: $!"; while ($client_address = accept(Client, Server)) {     # ... }









See Also

The getsockname function in Chapter 3 of Programming Perl and in perlfunc (1); the documentation for the standard Socket and IO::Socket modules; the section on "Sockets" in Chapter 6 of Programming Perl or perlipc (1)


Previous: 17.13. Non-Forking Servers Perl Cookbook Next: 17.15. Making a Daemon Server
17.13. Non-Forking Servers Book Index 17.15. Making a Daemon Server

Library Navigation Links

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