Few computers (or computer users, for that matter) are content to remain isolated from the rest of the world. Networking, once mostly limited to government research labs and computer science departments at major universities, is now available to virtually everyone, even home computer users with a modem and dial-up SLIP or PPP service. More than ever, networking is now used daily by organizations and individuals from every walk of life. They use networking to exchange email, schedule meetings, manage distributed databases, access company information, grab weather reports, pull down today's news, chat with someone in a different hemisphere, or advertise their company on the Web.
These diverse applications all share one thing in common: they use TCP networking, the fundamental protocol that links the Net together.[1] And we don't just mean the Internet, either. Firewalls aside, the underlying technology is the same whether you're connecting far across the Internet, between your corporate offices, or from your kitchen down to your basement. This means you only have to learn one technology for all sorts of application areas.
[1] Actually it's IP (Internet Protocol) that ties the Internet together, but TCP/IP is just a layer on top of IP.
How can you use networking to let an application on one machine talk to a different application, possibly on a totally different machine? With Perl, it's pretty easy, but first you should probably know a little bit about how the TCP networking model works.
Even if you've never touched a computer network before in your whole life, you already know another connection-based system: the telephone system. Don't let fancy words like "client-server programming" put you off. When you see the word "client," think "caller"; when you see the word "server," think "responder." If you ring someone up on the telephone, you are the client. Whoever picks up the phone at the other end is the server.
Programmers with a background in C programming may be familiar with sockets. A socket is the interface to the network in the same sense that a filehandle is the interface to files in the filesystem. In fact, for the simple stream-based clients we're going to demonstrate below, you can use a socket handle just as you would a filehandle.[2]
[2] Well, almost; you can't seek on a socket.
You can read from the socket, write to it, or both. That's because a socket is a special kind of bidirectional filehandle representing a network connection. Unlike normal files created via open
, sockets are created using the low-level socket
function.
Let's squeeze a little more mileage out of our telephone model. When you call into a big company's telephone switchboard, you can ask for a particular department by one name or another (such as "Personnel" or "Human Resources"), or by an exact number (like "extension 213"). Think of each service running on a computer as a department in a large corporation. Sometimes a particular service has several different names, such as both "http" and "www," but only one number, such as 80. That number associated with a particular service name is its port. The Perl functions getservbyname
and getservbyport
can be used to look up a service name given its port number, or vice versa. Here are some standard TCP services and their port numbers:
Service | Port | Purpose |
---|---|---|
echo | 7 | Accepts all input and echoes it back |
discard | 9 | Accepts anything but does nothing with it |
daytime | 13 | Return the current date and time in local format |
ftp | 21 | Server for file transfer requests |
telnet | 23 | Server for interactive telnet sessions |
smtp | 25 | Simple mail transfer protocol; the mailer daemon |
time | 37 | Return number of seconds since 1900 (in binary) |
http | 80 | The World Wide Web server |
nntp | 119 | The news server |
Although sockets were originally developed for Berkeley UNIX, the overwhelming popularity of the Internet has induced virtually all operating-systems vendors to include socket support for client-server programming. For this book, directly using the socket
function is a bit low-level. We recommend that you use the more user-friendly IO::Socket module,[3] which we'll use in all our sample code. This means we'll also be employing some of Perl's object-oriented constructs. For a brief introduction to these constructs, see Chapter 19, CGI Programming. The perltoot (1) manpage and Chapter 5 of Programming Perl offer a more complete introduction to object-oriented programming in Perl.
[3] IO::Socket is included as part of the standard Perl distribution as of the 5.004 release. If you're running an earlier version of Perl, just fetch IO::Socket from CPAN, where you'll find modules providing easy interfaces to the following services: DNS,ftp, Ident (RFC 931), NIS and NISPlus, NNTP, ping, POP3, SMTP, SNMP, SSLeay, telnet, and time - just to name a few.
We don't have the space in this book to provide a full TCP/IP tutorial, but we can at least present a few simple clients. For servers, which are a bit more complicated, see Chapter 6 of Programming Perl, or the perlipc (1) manpage.
For our simplest client, we'll choose a rather boring service, called "daytime." The daytime server sends a connecting client one line of data containing the time of day on that remote server, then closes the connection.
Here's the client:
#!/usr/bin/perl -w use IO::Socket; $remote = IO::Socket::INET->new( Proto => "tcp", PeerAddr => "localhost", PeerPort => "daytime(13)", ) or die "cannot connect to daytime port at localhost"; while ( <$remote> ) { print }
When you run this program, you should get something back that looks like this:
Thu May 8 11:57:15 1997
Here are what those parameters to the new
constructor mean:
Proto
The protocol to use. In this case, the socket handle returned will be connected to a TCP socket, because we want a stream-oriented connection, that is, one that acts pretty much like a plain old file. Not all sockets are of this type. For example, the UDP protocol can be used to make a datagram socket, used for message-passing.
PeerAddr
The name or Internet address of the remote host the server is running on. We could have specified a longer name like www.perl.com, or an address like 204.148.40.9. For demonstration purposes, we've used the special hostname localhost
, which should always mean the current machine you're running on. The corresponding Internet address for localhost is 127.0.0.1, if you'd rather use that.
PeerPort
This is the service name or port number we'd like to connect to. We could have gotten away with using just daytime
on systems with a well-configured system services file,[4] but just in case, we've specified the port number (13) in parentheses. Using just the number would also have worked, but numbers as constants make careful programmers nervous.
[4] The system services file is in /etc/services under UNIX.
Notice how the return value from the new
constructor is used as a filehandle in the while
loop? That's what's called an indirect filehandle, a scalar variable containing a filehandle. You can use it the same way you would a normal filehandle. For example, you can read one line from it this way:
$line = <$handle>;
All remaining lines from it this way:
@lines = <$handle>;
And send a line of data to it this way:
print $handle "some data\n";