Pages

Tuesday, April 29, 2003

Perl IO::Sockets


Introduction to IO::Sockets

A client and server program works this way. Simply put, a client requests a service and a server services the request. There are several ways to do this. The crudest will be to call a program within Perl and pass the parameters during the call. Another way is to use pipes.

A program can call another program but the input to the called program will be passed through the STDIN of the other program. Both methods are crude and allow only for simple passing of input and output. Another way to do this is using sockets.

Sockets allow two programs to communicate with each other. The server binds a port on the machine. The client connects to that port to communicate with the server,

IO:Socket Module

Perl has a module that simplifies socket communication. It is called IO::Socket. Simply put, the client has to connect to the server socket. The server meanwhile has to get the port and listen to
anything coming in on that socket.

Server script

The server is the program that listens to a request and processes the request. For our exercise, we will write a simple server that accepts numbers and adds all numbers up. (I know, you might as well do this in the client program but this is just an illustration)

The script has to do the following:

  • Open the listening socket by specifying the protocol, local host address and the port
  • Actually listen to any requests
  • When a request is accepted, process the request
  • Return the result to the client 
Simple!

The code to do this is as follows:

use IO::Socket;
#####################################
# Server Script: 
# Copyright 2003 (c) Philip Yuson 
# this program is distributed according to 
# the terms of the Perl license
# Use at your own risk
#####################################
$local = IO::Socket::INET->new(
                Proto     => 'tcp',             # protocol
                LocalAddr => 'localhost:8081',  
  # Host and port to listen to
                # Change the port if 8081 is being used
                Reuse     => 1
                ) or die "$!";
$local->listen();       # listen
$local->autoflush(1);   # To send response immediately
print "At your service. Waiting...\n";
my $addr;       # Client handle
while ($addr = $local->accept() ) {     # receive a request
        print   "Connected from: ", $addr->peerhost();  
 # Display messages
        print   " Port: ", $addr->peerport(), "\n";
        my $result;             # variable for Result
        while (<$addr>) {       # Read all messages from client 
                                # (Assume all valid numbers)
                last if m/^end/gi;      # if message is 'end' 
                                        # then exit loop
                print "Received: $_";   # Print received message
                print $addr $_;         # Send received message back 
                                        # to verify
                $result += $_;          # Add value to result
        }
        chomp;                  # Remove the 
        if (m/^end/gi) {        # You need this. Otherwise if 
                                # the client terminates abruptly
                                # The server will encounter an 
                                # error when it sends the result back
                                # and terminate
                my $send = "result=$result";    # Format result message
                print $addr "$send\n";          # send the result message
                print "Result: $send\n";        # Display sent message
        }
        print "Closed connection\n";    # Inform that connection 
                                        # to client is closed
        close $addr;    # close client
        print "At your service. Waiting...\n";  
# Wait again for next request
}

Save this as server.pl.

Start a command window and run this. The output should show something like this:

At your
service. Waiting...


This means that the server is listening to any request on the given port.

Client Script

The client drives the process. It sends a request to the server. It has to connect to the port the server is listening to. It should then receive some form of input from STDIN to send to the server. At the end, it sends an 'end' message to the server.

To illustrate interactive communication, the server will echo back anything it receives from the client. The client then verifies this against what it sent. If it does not match, then it is an error.
When the client receives an 'end' from STDIN, it receives the result from the server and prints out the result.

Ready for the code?

use IO::Socket;
#####################################
# Client Script:
# Copyright 2003 (c) Philip Yuson
# this program is distributed according to
# the terms of the Perl license
# Use at your own risk
#####################################
$remote = IO::Socket::INET->new(
                Proto   => 'tcp',       # protocol
                PeerAddr=> 'localhost', # Address of server
                PeerPort=> "8081",      # port of server
                Reuse   => 1,
                ) or die "$!";
print "Connected to ", $remote->peerhost, # Info message
      " on port: ", $remote->peerport, "\n";
$remote->autoflush(1);  # Send immediately
while (<>) {    # Get input from STDIN
        print $remote $_;       # Send to Server
        last if m/^end/gi;      # If 'end' then exit loop
        my $line = <$remote>;   # Receive echo from server
        if ($line ne $_) {      # If not the same as input
                print "Error in sending output\n"; # error
                exit;           # Terminate
        }
}
my $res = <$remote>;            # Receive result from server
$res =~ m/result=(\d*)/gi;      # Get the numeric result from message
print "Result: $1\n";           # Print the result
print "End of client\n";        # End of client
close $remote;                  # Close socket

Save this as client.pl.

Start another command window and run this. Make sure that the server.pl is running also.

The client should display something like this:
Connected
to 127.0.0.1 on port: 8081


Type in any set of numbers and press &lt;Enter&gt; each time. When you are done, type end and press &lt;Enter&gt;. Look at the result. The server should return the right computation.

Where can you use this?

The server can take the place of say a tax calculation routine where you send all the relevant numbers and at the end receive the calculated tax.


The server can also be modified to perform database access and return the result to the client. The
client can send a message like select tablename. The server can then format the proper SQL statement to get the rows. With this method, programmers on the client side need not worry about SQL statements because the programmers with SQL skills can write the SQL statements on the server side.

No comments:

Post a Comment