ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



12.2 Socket API and IO::Socket

Perl provides native support for sockets and a module called Socket to smooth some of the rough edges associated with the native socket call. It turns out that there are still a large number of options to deal with, and since most applications use a fairly standard set of options, we instead use a truly convenient module called IO::Socket, which is built on Socket.

This section uses this module to build a sending and receiving program.

12.2.1 Receiver

Just as you would ask the phone company for a telephone number and a physical handset, both sender and receiver ask the module to create sockets. Sockets, like telephones, are bidirectional endpoints: once a connection is established, either side can send and receive data, as long as there is an understanding between the two programs about the direction of communication.

Because only the receiving side needs to have a well-known address, we create a receiving socket as follows:

use IO::Socket;
$sock = new IO::Socket::INET (LocalHost => 'goldengate',
                              LocalPort => 1200,
                              Proto     => 'tcp',
                              Listen    => 5,
                              Reuse     => 1,
                             );
die "Could not connect: $!" unless $sock;

The IO::Socket::INET module provides a nice wrapper for Internet domain sockets. The LocalHost and LocalPort parameters specify the host and port on which this socket is going to listen. The number 1200 is chosen arbitrarily, but you must make sure that it doesn't conflict with the port number used by some other application on that machine (otherwise, you get an error saying, "Address already in use"). We set the Reuse option, because if this program ends without properly closing the socket and is subsequently restarted, it will complain about the socket being in use. The Listen option specifies the maximum number of callers that can be put on hold while they are dialing this number, figuratively speaking.

Once created, the socket is all set to receive incoming calls. The accept() method listens on the given port until another program attempts to connect to it (we'll shortly see the calling side to see how this is done); at this point, accept returns a new socket:

$new_sock = $sock->accept();

This is analogous to a switchboard operator indicating a different handset for you to converse on, while he goes back to waiting for the main number to ring. Messages sent by the client can now be obtained by reading from $new_sock. You can use this socket as a filehandle and call any of the input operators, <> , read, or sysread, like this:

$buf = <$new_sock>;
# or, 
$bytes_read = sysread ($new_sock, $buf, $num_bytes_to_read);

Both return undef on an end of file condition.

The following code summarizes the above discussion. It binds a socket to an address and waits for an incoming connection request. When that happens, it reads the new socket created until the other end closes its end of the connection. At this point, the <> operator returns undef (sysread returns 0, the number of bytes read).

use IO::Socket;
$sock = new IO::Socket::INET (LocalHost => 'goldengate',
                              LocalPort => 1200,
                              Proto     => 'tcp',
                              Listen    => 5,
                               Reuse     => 1                             
                             );
die "Socket could not be created. Reason: $!" unless $sock;
while ($new_sock = $sock->accept()) {
    while (defined ($buf = <$new_sock>)) {
       print $buf;
    }
}
close ($sock);

You can also use $new_sock->get_line() instead of <$new_sock>.

12.2.2 Sender

The calling side is even simpler. It creates a socket giving it the receiver's address and, if successful, starts sending data to it:

use IO::Socket;
$sock = new IO::Socket::INET (PeerAddr => 'goldengate',
                              PeerPort => 1200,
                              Proto    => 'tcp',
                             );
die "Socket could not be created. Reason: $!\n" unless $sock;
foreach (1 .. 10) {
    print $sock "Msg $_: How are you?\n";
}
close ($sock);

Notice how the parameters to the IO::Socket::INET::new method define whether it is a server- or client-side socket. The Listen and Reuse parameters are ignored for sending ports.

12.2.3 Bidirectional Communications

You can read and write from sockets, but as the preceding scripts show, two communicating processes must have a common understanding of who is doing the talking and who the listening. The programs can deadlock if both are too polite and start reading their respective sockets (sysread and other input operators wait until they are able to read the requisite amount of data). They can also deadlock if both are too impolite and start speaking into the phone at the same time, figuratively speaking (syswrite blocks once the buffers fill up, and because the other end is not listening, deadlock is a likely possibility). In a typical client/server setup, this protocol is well established. The client program initiates the conversation, makes a request, and waits for an answer. The typical server never attempts to connect to a client program or initiate requests; it listens and responds. Deadlocks thus happen only in peer-peer conversations.