Summary


 
Network Programming with Perl
By Lincoln  D.  Stein
Slots : 1
Table of Contents
Chapter  22.   UNIX-Domain Sockets

    Content

Using UNIX-Domain Sockets for Datagrams

UNIX-domain sockets can be used to send and receive datagrams. When creating the socket (or accepting IO::Socket::UNIX's default), instead of specifying a type of SOCK_STREAM, create the socket with SOCK_DGRAM . You will now be able to use send() and recv() to transmit messages over the socket without establishing a long- term connection.

Because UNIX-domain sockets are local to the host, there are some important differences between using UNIX-domain sockets to send datagrams locally and using the UDP protocol to send datagrams across the network. On the plus side, UNIX-domain datagrams are reliable and sequenced . Unlike with the UDP protocol, you can count on the UNIX-domain datagrams reaching their destinations and arriving in the same order you sent them. On the minus side, two-way communication is only possible if both processes bind() to a path . If the client forgets to do so, then it will be able to send messages to the server, but the server will not receive a peer address that can be used to reply.

To illustrate using datagrams across UNIX-domain sockets, we'll develop a simple variation on the daytime server. This server acts much like the standard daytime server by returning a string containing the current local date and time in response to incoming requests . However, in a nod to globalization, it also looks at the incoming message for a string indicating the time zone, and if the string is present, it returns the date and time relative to that zone.

The server is called localtime_serv.pl and the client localtime_cli.pl . The client takes an optional time-zone argument on the command line. The following excerpt shows the client being used to fetch the time in the current time zone, in Eastern Europe, and in Anchorage, Alaska:

 % ./localtime_cli.pl Sat Jun 17 18:06:14 2000 % ./localtime_cli.pl Europe/Warsaw Sat Jun 17 22:06:24 2000 % ./localtime_cli.pl America/Anchorage Sat Jun 17 14:06:57 2000 

UNIX-Domain Daytime Server

Figure 22.3 lists localtime_serv.pl . It follows the general outline of the single-threaded datagram servers discussed in Chapter 18.

Figure 22.3. localtime_serv.pl , the daytime server

graphics/22fig03.gif

Lines 1 “6: Server setup We load the IO::Socket module and choose a default path for the socket. We then read the command line for an alternative socket path, should the user desire to change it.

Line 7: Install TERM and INT handlers As in the connection-oriented example, we need to delete the socket file before exiting. In the previous case we did this by unlinking the file in the TERM and INT signal handlers.

For variety, in this example we will accomplish the same thing by defining an END{} block that unlinks the path when the script terminates. However, to prevent the script from terminating prematurely, we must still install an interrupt handler that intercepts the TERM and INT signals and calls exit() so that the process terminates in an orderly fashion.

Lines 8 “12: Create socket We set our umask to 0111 so that the socket will be world writable and call IO::Socket::UNIX->new() to create the socket and bind it to the designated path. Unlike the previous example, where we allowed IO::Socket::UNIX to default to a connection-oriented socket, we pass new() a Type argument of SOCK_DGRAM . Because this is a message-oriented socket, we do not provide a Listen argument.

Lines 13 “22: Transaction loop We enter an infinite loop. Each time through the loop we call recv() to return a message of up to 128 bytes (which is as long as a time zone specifier is likely to get). The value returned from recv() is the path to the peer's socket.

We examine the contents of the message, and if its format is compatible with a time-zone specifier, we use it to set the TZ environment variable, which contains the current time zone. Otherwise, we delete this variable, which causes Perl to default to the local time zone.

Using the peer's path, we now call send() to return to the peer a datagram containing the output of localtime() . If for some reason send() returns a false value, we issue a warning.

Line 23: END{} block The script's END{} block unlinks the socket file if $path is not empty.

UNIX-Domain Daytime Client

A client to match the daytime server is shown in Figure 22.4.

Figure 22.4. localtime_cli.pl , the daytime client

graphics/22fig04.gif

Lines 1 “4: Load modules We load the IO::Socket and Getopt::Long modules. We also bring in the tmpnam() function from the POSIX module. This handy routine chooses unique names for temporary files; we'll use it to generate a file path for our local socket.

Lines 5 “6: Constants We define a constant containing the default path to use for the server's socket, and a TIMEOUT value containing the maximum time we will wait for a response from the server.

Lines 7 “10: Select pathnames for local and remote sockets We process command-line options looking for a -- path argument. If none is defined, we default to the same path for the server socket that the server uses.

We also need a pathname for the local socket so that the server can talk back to us, but we don't want to hard code the path because another user might want to run the client at the same time. Instead, we call POSIX::tmpnam() to return a unique temporary filename for the local socket.

Line 11: Signal handlers We will unlink the local socket in an END{} block as in the server. For this reason, we intercept the INT and TERM signals.

Lines 12 “16: Create socket We set our umask as before and call IO::Socket::UNIX->new() to create the socket, providing both Local and Type arguments to create a SOCK_DGRAM socket bound to the temporary pathname returned by tmpnam() .

Lines 17 “18: Prepare to transmit request We recover the requested time zone from the command line. If none is provided, we create a message consisting of a single space (we must send at least 1 byte of data to the server in order for it to respond). We use sockaddr_un() to create a valid destination address for use with send() .

Lines 19 “27: Send request and receive response We call send() to send the message containing the requested time zone to the server.

We now want to call recv() to read the response from the server, but we don't know for sure that the server is listening. So instead of calling recv() and waiting indefinitely for a response, we wrap the call in an eval{} block using the technique shown in Chapter 5. On entry into the eval{} , we set a handler for the ALRM signal, which calls die() . We then set an alarm clock for TIMEOUT seconds using alarm() and call recv() . If recv() returns before the alarm expires , we print the returned data. Otherwise, we die with an error message.

Line 28: END{} block As in the server, we unlink the local socket after we are done.

If you wish to watch the client's timeout mechanism work, start the server and immediately suspend it using the suspend key ( ^Z on UNIX systems). When the client sends a request to the server, it will not get a response and will issue a timeout error.


   
Top


Network Programming with Perl
Network Programming with Perl
ISBN: 0201615711
EAN: 2147483647
Year: 2000
Pages: 173

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net