Perl offers a host of functions for accessing the socket-based interprocess communication facilities. The system facilities on UNIX systems are available to the Perl programmer and, thus, can be called directly from Perl scripts. Given the information in this chapter, you should be able to write your own client/server Perl applications using sockets.
Perl offers a host of functions for accessing the socket functions on a UNIX-based system. It's essential to cover some of the important features of interprocess communications in order to understand how the model fits in with Perl. Given the limited amount of space in a chapter, I cannot hope to possibly cover all the bases for socket programming. However, I will cover the basics, and you should have enough information from this chapter to develop your own client/server model using Perl.
The absolutely best reference to doing anything with network programming is UNIX Network Programming by W. Richard Stevens (Prentice Hall, ISBN 0-13-949876-1). The book provides programs and C code samples in excruciating detail that cover all aspects of network programming. BSD UNIX gives many ways to open, use, and close sockets, and this book covers them all. The examples presented in this chapter are derived from the C code in this book. Perl is great in that often you can do a line-by-line mapping of cookbook socket and network function calls in C to equivalent calls in Perl. (Someone ought to write an interpreter!) Please refer to Stevens's book for a more detailed discussion on internetworking with sockets.
In general, socket programming is based on the client/server model. A client is a program that makes requests to the server to get responses. A server is simply another program that responds to these requests. The server either can reside on the same computer as the client or can be a computer somewhere on a connecting network. Sending requests and receiving replies to transfer the data between clients and servers is the protocol with which they communicate.
A common protocol in the UNIX world is the TCP/IP protocol. The Internet Protocol (IP) handles the transfer of data from one computer to another over a network. The Transport Control Protocol (TCP) offers a set of reliability and connection functions that IP does not offer. Messages sent via TCP/IP from one computer are acknowledged by the other computer. The acknowledgment of sent messages increases reliability, but at the cost of efficiency. The User Datagram Protocol (UDP) is like TCP in sending messages, but has no acknowledge feature as such. This makes UDP faster when receiving acknowledgments is not as high of a priority as sending acknowledgments back. UDP tends to be less reliable than TCP because the sender UDP does not have a guarantee that the sent message even made it to the remote site. Think of UDP as the regular U.S. Mail service and TCP/IP as a registered letter service. Although the U.S. Mail is generally very reliable, a sender does not really know if the recipient did indeed receive the letter. As far as you are concerned, the letter got to its destination, and if it didn't the recipient will request another. This is similar to UDP. Send a message, and if it doesn't make it over to the destination-no problem-the recipient will ask again. When sending important documents though, you would most likely want to get a confirmation from the recipient. In this case, you'd normally use a registered letter service, which will return a signed receipt. The signed receipt is your "acknowledgment" in TCP/IP.
Most applications using TCP or UDP have a port number that they talk on to get the service they want. A machine assigns one unique port number to an application. Port numbers are standardized enough to identify the type of service being used. On UNIX systems, the file /etc/services maintains a list of services offered on each port. Port numbers between 1 and 255 are reserved for standard, well-known applications. There are well-known port numbers that everyone recognizes: for example, port 80 for the World Wide Web's server daemons, the nameserver on port 42, sendmail at port 25, and so on. In all cases, avoid using socket 0, since it's interpreted differently on different systems.
Two computers talk to each other via a network circuit. Each circuit is uniquely identified by a combination of two numbers called a socket. Basically a socket is the IP address of the machine plus the port number used by the TCP software.
There are two ways of defining the address: If two processes talking to each other are on the same machine, the "family" of protocols is referred to as AF_UNIX. If the communicators are on different machines, this is referred to as the AF_INET family. In the AF_UNIX family, sockets are assigned a pathname in the directory tree. In the AF_INET family, they are assigned a port number and application number. Using AF_INET, you can talk to processes on the same machine, but AF_UNIX is reserved for the same machine.
There are two types of sockets about which you should know:
There is a socket on both the sending and receiving machine. Clients send on their sockets, and servers listen on their sockets and accept connections when necessary. The IP address of each machine is guaranteed to be unique by design, and the port numbers are unique to each machine. This implies the socket numbers, which are a combination of these two unique numbers, will also be unique across the network. This allows two applications to communicate using unique socket numbers.
With Perl, it's possible to get access to these socket and network functions. Most of this chapter has a UNIX slant to it. On NT machines, you'll be dealing with the Remote Access Server and WinSock under Windows. Please refer to the technical notes from Microsoft for more information on WinSock programming.
The protocols available on your UNIX system are located in the /etc/protocols file. You have to use three functions to read this file. The function setprotoent() starts the listing process. The Perl function getprotoent() reads one line from the /etc/protocols file and lists it for you. Successive calls to the function read successive lines. Finally, a call to endprotoent() stops the listening process. A simple way to have all the protocols available to your Perl script is to use the script shown in Listing 12.1.
Listing 12.1. Showing available protocols.
1 #!/usr/bin/perl
2 #
3 # List all the protocols in this machine
4 #
5 setprotoent(1);
6 while (($name, $aliases, $protonum) = getprotoent) {
7 print " Name=$name, Aliases=$aliases, Protocol=$protonum \n";
8 }
9 endprotoent;
The output should be similar to what is shown here:
Name=ip, Aliases=IP, Protocol=0
Name=icmp, Aliases=ICMP, Protocol=1
Name=igmp, Aliases=IGMP, Protocol=2
Name=ggp, Aliases=GGP, Protocol=3
Name=tcp, Aliases=TCP, Protocol=6
Name=pup, Aliases=PUP, Protocol=12
Name=udp, Aliases=UDP, Protocol=17
Name=idp, Aliases=IDP, Protocol=22
Name=raw, Aliases=RAW, Protocol=255
To keep the file open between successive calls to the getprotoent() call, you should call the setprotoent() function with a nonzero parameter. To stop querying the file, use the endprotoent() call.
To determine whether you have a specific protocol present, you can use the system call getprotobyname or getprotobynumber. A return value of NULL indicates that the protocol is not there. The name passed to the function is not case-sensitive. Therefore, to list the names, aliases, and the protocol number for TCP, you can use this:
if (($name, $aliases, $protonum) = getprotobyname('tcp')) {
print "\n Name=$name, Aliases=$aliases, Protocol=$protonum";
}
print "\n"
A comparable set of calls is available for determining what services are available for your machine. This call queries the /etc/services file. Listing 12.2 illustrates how to use these calls. The setservent call with a nonzero file rewinds the index into the services file for you, the getservent gets the four items in the service entry, and the endservent call terminates the lookup. The output from this file can be a bit lengthy and is shown in Listing 12.2 starting at line 15.
In Listing 12.2, lines 1 and 2 clear the screen and show the output of the showme.pl file with the script in it. At line 13, we execute this script. Your output may be different than the one shown in Listing 12.2 depending on what services you have installed on your system.
Listing 12.2. Listing server services.
1 $ clear
2 $ cat showme.pl
3 #!/usr/bin/perl
4 setservent(1);
5 printf "%15s %15s %4s %15s\n",
6 "Name","Aliases","Port","Protocol";
7 while(($nm,$al,$pt,$pr) = getservent) {
8 # print "Name=$nm, Aliases=$al, Port=$pt, $Protocol=$pr\n";
9 printf "%15s %15s %4d %15s\n", $nm,$al,$pt,$pr;
10 }
11 endservent;
12 $
13 $
14 $ showme.pl
15 Name Aliases Port   ;Protocol
16 tcpmux 1 tcp
17 echo 7 tcp
18 echo 7 udp
19 discard sink null 9 tcp
20 discard sink null 9 udp
21 systat users 11 tcp
22 daytime 13   ; tcp
23 daytime 13   ; udp
24 netstat 15   ; tcp
25 qotd quote 17 tcp
26 msp 18 tcp
27 msp 18 udp
28 chargen ttytst source 19 tcp
29 chargen ttytst source 19 udp
30 ftp 21 tcp
31 telnet 23 tcp
32 smtp mail 25 &nbs p; tcp
33 time timserver 37 tcp
34 time timserver 37 udp
35 rlp resource 39 udp
36 nameserver name 42 &nbs p; tcp
37 whois nicname 43 tcp
38 domain nameserver 53 &n bsp; tcp
39 domain nameserver 53 &n bsp; udp
40 mtp 57 tcp
41 bootps 67 tcp
42 bootps 67 udp
43 bootpc 68 tcp
44 bootpc 68 udp
45 tftp 69&n bsp; udp
46 gopher 70 tcp
47 gopher 70 udp
48 rje netrjs 77 tcp
49 finger 79 tcp
50 www http 80 tcp
51 www 80 udp
52 link ttylink 87 & nbsp; tcp
53 kerberos krb5 88 tcp
54 kerberos 88 &nbs p; udp
55 supdup 95 tcp
56 hostnames hostname 101 tcp
57 iso-tsap tsap 102 tcp
58 csnet-ns cso-ns 105 tcp
59 csnet-ns cso-ns 105 udp
60 rtelnet 107 &nbs p; tcp
61 rtelnet 107 &nbs p; udp
62 pop2 postoffice 109 tcp
63 pop2 109 & nbsp; udp
64 pop3 110 & nbsp; tcp
65 pop3 110 & nbsp; udp
66 sunrpc 111   ; tcp
67 sunrpc 111   ; udp
68 auth tap ident authentication 113 tcp
69 sftp 115 & nbsp; tcp
70 uucp-path 117 tcp
71 nntp readnews untp 119 tcp
72 ntp 123 tcp
73 ntp 123 udp
74 netbios-ns 137 & nbsp; tcp
75 netbios-ns 137 & nbsp; udp
76 netbios-dgm 138 tcp
77 netbios-dgm 138 udp
78 netbios-ssn 139 tcp
79 netbios-ssn 139 udp
80 imap2 143 tcp
81 imap2 143 udp
82 snmp 161 & nbsp; udp
83 snmp-trap snmptrap 162 udp
84 cmip-man 163 &nb sp; tcp
85 cmip-man 163 &nb sp; udp
86 cmip-agent 164 & nbsp; tcp
87 cmip-agent 164 & nbsp; udp
88 xdmcp 177 tcp
89 xdmcp 177 udp
90 nextstep NeXTStep NextStep 178 tcp
91 nextstep NeXTStep NextStep 178 udp
92 bgp 179 tcp
93 bgp 179 udp
94 prospero 191 &nb sp; tcp
95 prospero 191 &nb sp; udp
96 irc 194 tcp
97 irc 194 udp
98 smux 199 & nbsp; tcp
99 smux 199 & nbsp; udp
100 at-rtmp 201 &nb sp; tcp
101 at-rtmp 201 &nb sp; udp
102 at-nbp 202 &nbs p; tcp
103 at-nbp 202 &nbs p; udp
104 at-echo 204 &nb sp; tcp
105 at-echo 204 &nb sp; udp
106 at-zis 206 &nbs p; tcp
107 at-zis 206 &nbs p; udp
108 z3950 wais 210 tcp
109 z3950 wais 210 udp
110 ipx 213 tcp
111 ipx 213 udp
112 imap3 220 tcp
113 imap3 220 udp
114 ulistserv 372 tcp
115 ulistserv 372 udp
116 exec 512 tcp
117 biff comsat 512 udp
118 login 513 tcp
119 who whod 513 udp
120 shell cmd 514 tcp
121 syslog 514 &nbs p; udp
122 printer spooler 515 tcp
123 talk 517 udp
124 ntalk 518 udp
125 route router routed 520 udp
126 timed timeserver 525 udp
127 tempo newdate 526 tcp
128 courier rpc 530 tcp
129 conference chat 531 tcp
130 netnews readnews 532 tcp
131 netwall 533 &nb sp; udp
132 uucp uucpd 540 tcp
133 remotefs rfs_server rfs 556 tcp
134 klogin 543 &nbs p; tcp
135 kshell 544 &nbs p; tcp
136 kerberos-adm 749 &nbs p; tcp
137 webster 765 &nb sp; tcp
138 webster 765 &nb sp; udp
139 ingreslock 1524   ; tcp
140 ingreslock 1524   ; udp
141 prospero-np 1525 tcp
142 prospero-np 1525 udp
143 rfe 5002 tcp
144 rfe 5002 udp
145 krbupdate kreg 760 tcp
146 kpasswd kpwd 761 tcp
147 eklogin 2105 &n bsp; tcp
148 supfilesrv 871 tcp
149 supfiledbg 1127   ; tcp
Tip |
The gethostent function was not implemented as of Perl 5.002. |
Perl also lets you look at the host name by address in your /etc/hosts file with the gethostbyaddr call. This function takes two parameters, the address to look up and the value of AF_INET. On most systems, this value is set to 2 but can be looked up in the /usr/include/sys/socket.h file. The gethostbyname("hostname") function returns the same values as the gethostbyaddr() call. The parameter passed into the function is the name of the host being looked up. Listing 12.3 illustrates how to do this.
In the program shown in Listing 12.3, the code in Line 4 gets the host name and alias given the address 204.251.103.2. You would use a different address, of course, because the address shown here is specific to my machine. Lines 6 through 10 print the components of the information you get back from the gethostbyaddr function call. Also, in lines 12 and 13, you can get the same information back using the node name instead of an IP address. Lines 14 through 19 print these values.
Listing 12.3. Sample listing to show usage of gethostbyname and gethostbyaddr.
1 #!/usr/bin/perl
2
3 $addr = pack('C4',204,251,103,2);
4 ($name,$alias,$atype,$len,@addrs) = gethostbyaddr($addr,2);
5 ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
6 print "Name : $name \n";
7 print "Alias: $alias \n";
8 print "Type : $atype \n";
9 print "Len : $len \n";
10 print "Node : $a.$b.$c.$d \n";
11
12 $name = "www.ikra.com";
13 ($name,$alias,$atype,$len,@addrs) = gethostbyname($name);
14 ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
15 print "Name : $name \n";
16 print "Alias: $alias \n";
17 print "Type : $atype \n";
18 print "Len : $len \n";
19 print "Node : $a.$b.$c.$d \n";
Note |
Note the use of the number 2 in the call to gethostbyaddr in Listing 12.3. This should be the constant $AF_INET. |
Enough already about getting information on your system. Let's see what socket functions are available to you. Depending on your site and what extensions you have for Perl, you may have more functions available. Check the man pages for socket for more information. Here are the most common ones you'll use:
I cover these functions in the following sections. However, there are some constants that must be defined before I continue. These constants are used in all function calls and scripts in this chapter. Feel free to change them to reflect your own system's peculiarities. Here's a list of the constants:
The socket() system call creates a socket for the client or the server. The socket function is defined as this:
socket(SOCKET_HANDLE, $FAMILY, $TYPE, $PROTOCOL);
The return value from this function is NULL, and if there was an error, you should check the $! for the type of error message. The call to open a socket looks like this:
socket(MY_HANDLE, $AF_UNIX, $STREAMS, $PROTOCOL) ||
die "\nCannot open socket: $!\n";
print "\nSocket successfully opened\n";
It's a good idea to unlink any existing file names for previously opened sockets with the unlink call:
unlink "$my_tst_srvr" || die "\n$O: No permissions";
You'll use the socket descriptor MY_HANDLE to refer to this socket in all subsequent network function calls in your program. Sockets are created without a name. Clients use the name of the socket in order to read or write to it. This is where the bind function comes in.
The bind() system call assigns a name to an unnamed socket:
bind(SOCKET_HANDLE, $nameAsAString);
bind(SOCKET_HANDLE, $sockaddr);
The first item is the socket descriptor you just created. The second parameter is the name that refers to this socket if you are using AF_UNIX or its address if you are using AF_INET.
The call to bind using AF_UNIX looks like this:
bind(MY_HANDLE,"./mysocket") || die "Cannot bind $!\n";
In AF_INET, it looks like this:
$port = 6666
$AF_INET=2; # Use AF_INET instead of AF_UNIX
($name,$alias,$atype,$len,$addr)=gethostbyname(`uname -n`);
$my_ip_addr = pack(S n C4 x8,$AF_INET,$STREAMS,$port,$addr);
bind(MY_HANDLE,$my_ip_addr) || die "Cannot bind $!\n";
The parameters' pack() function probably needs some explanation. The pack() function takes two parameters: a list of formats to use and a list of values to pack into one continuous stream of bytes. In our case, the bind() call expects a sockaddr structure of the following form in a C structure:
{
unsigned short family;
int network;
long address;
char nullbytes[8];
}
The first parameter to the pack instruction can take the values listed in Table 12.1. Check the man pages for the pack instruction for more details. You had the pack instruction create the socket address structure for you. Therefore, the script uses S n C4 x8 to pack a signed short, followed by an integer in network order, four unsigned characters, and eight NULL characters to get this call:
pack(S n C4 x8,$AF_INET,$STREAMS,$port,$addr);
Type of Packing | |
Null fill to absolute position | |
An ASCII string, padded with NULLs | |
An ASCII string, padded with spaces | |
A bit string in ascending bit order | |
A bit string in descending bit order | |
A signed char value | |
An unsigned char value | |
A double-precision float in the native format | |
A single-precision float in the native format | |
A hex string, high nibble first | |
A hex string, low nibble first | |
A signed integer value | |
An unsigned integer value | |
A signed long value | |
An unsigned long value | |
A long in network order | |
A short in network order | |
A pointer to a null-terminated string | |
A pointer to a structure (fixed-length string) | |
A signed short value | |
An unsigned short value | |
A uuencoded string | |
A long in little-endian order | |
A short in little-endian order | |
A null byte | |
Back up a byte |
Now that you have bound an address for your server or client, you can connect to it or listen for connections with it. If your program is a server, it will set itself up to listen and accept connections.
Tip |
Do not use S n A4 x8 instead of S n C4 x8 for packing into the sockaddr structure. The C4 specifies four unsigned char data values and is safe to use. The A4 implies a string, which may confuse the pack() function if there are nulls (zeroes) in the address. |
Now let's look at the functions available for use in a server.
The listen() system call is used by the server to listen for connections. Once it is ready to listen, the server is able to honor any requests for connections with the accept system call. The listen call is defined as this:
listen(SOCKET_HANDLE, $queueSize);
The SOCKET_HANDLE is the descriptor of the socket you created. The queueSize is the number of waiting connections allowed at one time before any are rejected. Use the standard value of 5 for queue size. A returned value of NULL indicates an error. The call to listen normally looks like this:
listen(MY_HANDLE,5) || die "Cannot listen $!\n";
If this call is successful, you can accept connections with the accept function, which looks like this:
accept(NEWSOCKET, ORIGINAL_SOCKET);
The accept() system call is used by the server to accept any incoming messages from a client's connect() calls. Be aware that this function will not return if no connections are received. As requests come off the queue and set up in the listen() call, the accept function handles them by assigning them to a new socket. NEWSOCKET is created by the accept function as ORIGINAL_SOCKET, but now NEWSOCKET is going to be used to communicate with the client. At this point, most servers fork off (fork()) a child process to handle the client and go back to wait for more connections. Before I get into that, let's see how connections are originated.
Let's look at the connect() call that you'll use to connect to a server.
The connect() system call is used by clients to connect to a server in a connection-oriented system. This connect() call should be made after the bind() call. There are two ways you can call the connect() call: one for AF_UNIX using the pathname of the socket and the other using an address as the AF_INET requirement for a socket handle.
connect(SOCKET_HANDLE,"pathname" ); # for AF_UNIX
connect(SOCKET_HANDLE,$Address); # for AF_INET
Given this background information about socket information gathering, creation, and so on, you are now ready to write your own server using Perl. Listing 12.4 presents a sample server.
Listing 12.4. Server side for connection-oriented protocol.
1 #!/usr/bin/perl
2 #
3 # Sample connection oriented server using Perl
4 #
5 $AF_UNIX = 1;
6 $AF_INET=2; # Use AF_INET instead of AF_UNIX.
7 $SOCK_STR = 1; # Use STREAMS.
8 $PROTOCOL = 0; # stick to the default protocols (IP).
9
10 $port = 6668 unless $port;
11
12 #
13 # The pattern for packing into a sockaddr structure
14 #
15 $PACKIT='S n C4 x8';
16
17 #
18 # Disable any buffering on any newly created sockets.
19 #
20 select(NEWSOCKET);
21 $| = 1;
22 select(stdout);
23
24 #
25 # Create the socket.
26 #
27 socket(MY_SOCKET, $AF_INET, $SOCK_STR, $PROTOCOL) ||
28 die "\n $0: Cannot open socket: $!";
29 print "Socket successfully opened\n";
30
31 #
32 # Get the host address for this node
33 #
34
35 ($name, $aliases, $addrtype, $len, @addrs) = gethostbyname("www.ikra.com");
36 ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
37 print "Server Name=$name, Server Address= $a.$b.$c.$d\n";
38 $my_ip_addr = pack($PACKIT,$AF_INET,$port,$addrs[0]);
39
40 #
41 # If you just want to test with the localhost, try this line
42 # instead of the above.
43 # $my_ip_addr = pack($PACKIT,$AF_INET,$port,127,0,0,1);
44
45 #
46 # Bind to the socket and listen on this port
47 #
48 bind(MY_SOCKET, $my_ip_addr) || die "$0: Cannot bind .. $!\n";
49 print "\n Bound to socket";
50 listen(MY_SOCKET,5) || die "$0: Cannot listen: $!\n";
51 print "\n Listening \n";
52
53 while(1) {
54 $remote = accept(NEWSOCKET, MY_SOCKET) || die "$0: Unacceptable: $!\n";
55
56 #
57 # In case you have to display incoming connection
58 # information, you can uncomment the next three lines of code:
59
60 # @remoteInfo = unpack($PACKIT,$remote);
61 # $, = ' ';
62 # print @remoteInfo; print "\n";
63
64 # $pid = fork || &cleanup;
65
66 if ($pid == fork) { # child
67 sleep 3;
68 print NEWSOCKET "Welcome to this server\n";
69 # in child,.. you can do other stuff here.
70 close NEWSOCKET;
71 # I chose to just print this message and terminate
72 close MY_SOCKET;
73 exit;
74 }
75 else { # parent
76 sleep 10;
77 close MY_SOCKET;
78 close NEWSOCKET; # in parent
79 exit;
80 }
81
82 }
83 sub cleanup { close NEWSOCKET; close(MY_SOCKET); die "$0: Cannot fork : $!\n"; }
Note |
Of course, instead of the IP addresses shown above in Listing 12.4, you would have to modify the Perl script to use your own machine name and IP address. Do not use the addresses shown in this example because they are coded to work with a specific machine with a specific name. |
In the case of connection-oriented protocols, the server does the following functions:
Once a connection to the server has been accepted, the client and server can exchange data with the read() and write() function calls. To read from the socket, use the function call
read(MY_SOCKET, $buffer, $length);
where SOCKET_HANDLE is the socket you are reading from and $buffer is where you will be putting in data of size $length. To write to the socket, you can use the function call
write(MY_SOCKET, $buffer, $length);
For sending just text data, you can use the print call instead. For example, the following code will write text to the socket:
print MY_SOCKET, "Hello, ..";
Once a connection has served its time, it has to be closed so that other clients are able to use the system resources. To close the socket, your server and clients should call the close() function:
close(MY_SOCKET);
The shutdown() function allows you to selectively shut down sends and receives on a socket. Here's the function call:
shutdown(MY_SOCKET,HOW);
When the HOW parameter is 0, no more data is received on this socket. If HOW is set to 1, no more data will be sent out on this socket. If set to 2, no data is received or sent on this socket. (You still have to close the socket, even if you shut it down for sending and receiving.)
Listing 12.5 presents a sample of the client side of things.
Listing 12.5. The client side.
1 #!/usr/bin/perl
2 #
3 # define constants for talking to server
4 #
5 $PACKIT = 'S n C4 x8';
6 $AF_INET = 2;
7 $SOCK_STR = 1; # STREAMS
8 $DEF_PROTO = 0; #default protocol of IP
9 $port = 6668 unless $port;
10
11 #
12 # Get the name of the server
13 #
14 ($name, $aliases, $addrtype, $len, @addrs) = gethostbyname("www.ikra.com");
15 ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
16 print "Server Name=$name, Server Address= $a.$b.$c.$d\n";
17 $that = pack($PACKIT,$AF_INET,$port,$addrs[0]);
18
19 #
20 # Confine yourself to the local host machine address of 127.0.0.1
21 #
22 $this = pack($PACKIT,$AF_INET,$port,127,0,0,1);
23
24 #
25 # Disable buffering on this socket.
26 #
27 select(CLIENT_SOCKET);
28 $| = 1;
29 select(stdout);
30
31
32 socket(CLIENT_SOCKET,$AF_INET,$SOCK_STR,$DEF_PROTO) ||
33 die "$0: Cannot open socket\n";
34 print "Created socket\n";
35
36 #
37 # Attempt to connect to server.
38 #
39 do
40 {
41 sleep(1);
42 $result = connect(CLIENT_SOCKET,$that);
43 if (result != 1) {
44 print "Sleeping\n";
45 }
46
47 } while ($result != 1);
48
49 sleep(5);
50 print "After connection\n";
51
52 #
53 # send data to server
54 #
55 # write(CLIENT_SOCKET,"hello",5);
56
57 read(CLIENT_SOCKET,$buf,100);
58
59 print "[" . $buf . "]\n";
60 close(CLIENT_SOCKET);
The client for connection-oriented communication also takes the following steps:
Tip |
After the connection is used up by the client, it's a good idea to close the socket so that others may use the system resources. |
That's about it for a client program. Any processing that has to be done is done while the connection is open. Client programs can be written to keep a connection open for a long time while large amounts of data are transferred. If there is too long of a delay between successive messages, clients would then open a socket connection, send the message or messages, and close the connection immediately after the acknowledgment, if any, arrives. This way, all sockets are opened only on an as needed basis and do not use up socket services when both the server and client are idle.
If you read more documentation on Perl and sockets, you'll see references to the socket.ph file. If you cannot find this file anywhere on your system, it's because you have not run the h2ph file on your include directories. This h2ph program converts C header files to Perl header files. The safest way to ensure that you have all the files converted to Perl headers is to issue the following statements while logged in as root:
$ cd /usr/include
$ h2ph *
$ h2ph sys/*
You may run into some problems while running this script. For instance, it will say that it's creating a .ph file from a .h file, but after execution, the *.ph file may not exist! Check the script in the h2ph file to see where $perlincl is pointing and if you have read/write permissions there. A common repository is the /usr/local/lib/perl5 or the /usr/lib/perl5 directory. Another thing to remember is that the @Inc variable in your Perl scripts should point to the same location where the *.ph files are placed.
The standard Perl 5 distribution comes with the Socket.pm module, which greatly speeds up Perl code development work. Look at the documentation in the /usr/lib/Perl5/Socket.pm file for more information. This module requires dynamic loading, so ensure that your system supports it.
Perl offers very powerful features for using sockets on UNIX machines. The system calls available offer enough power and flexibility to create client/server applications in Perl without having to write code in a compiled language.
The functions available in Perl include those for querying available system services and protocols, IP addresses, and other host name information. Here are a few key points to remember when working with Perl and sockets: