Tuesday, 4 March 2014

Networking with Perl.

One of the reasons the Internet has blossomed so quickly is because everyone can understand the protocols that are spoken on the net. A protocol is a set of commands and responses. There are two layers of protocols that I'll mention here. The low-level layer is called TCP/IP and while it is crucial to the Internet, we can effectively ignore it. The high-level protocols like ftp, smtp, pop, http, and telnet are what you'll read about in this chapter. They use TCP/IP as a facilitator to communicate between computers. The protocols all have the same basic pattern:
·                  Begin a Conversation -- Your computer (the client) starts a conversation with another computer (the server).
·                  Hold a Conversation -- During the conversation, commands are sent and acknowledged.
·                  End a Conversation -- The conversation is terminated.

Network Protocol Communications Model
Internet conversations are done with sockets, in a manner similar to using the telephone or shouting out a window. I won't kid you, sockets are a complicated subject. They are discussed in the "Sockets" section that follows. Fortunately, you only have to learn about a small subset of the socket functionality in order to use the high-level protocols.
A list of the high-level protocols that you can use is given below with the protocol number in brackets. (We will not be able to cover them all here, but if you'd like to investigate further, the protocols are detailed in documents at the http://ds.internic.net/ds/dspg0 intdoc.html Web site.)

 auth
(113) -- Authentication
echo
(7) -- Checks server to see if they are running
finger
(79) -- Lets you retrieve information about a user
ftp
(21) -- File Transfer Protocol
nntp
(119) -- Network News Transfer Protocol: Usenet News Groups
pop
(109) -- Post Office Protocol - incoming mail
smtp
(25) -- Simple Mail Transfer Protocol: outgoing mail
time
(37) -- Time Server
telnet
(23) -- Lets you connect to a host and use it as if you were a directly connected terminal
Each protocol is also called a service. Hence the term, mail server or ftp server. Underlying all of the high-level protocols is the very popular Transfer Control Protocol/Internet Protocol or TCP/IP. You don't need to know about TCP/IP in order to use the high-level protocols. All you need to know is that TCP/IP enables a server to listen and respond to an incoming conversation. Incoming conversations arrive at something called a port. A Port is an imaginary place where incoming packets of information can arrive (just like a ship arrives at a sea port). Each type of service (for example, mail or file transfer) has its own port number.
If you have access to a UNIX machine, look at the /etc/services file for a list of the services and their assigned port numbers. Users of Windows 95-and, I suspect Windows NT-can look in \windows\services.
In this chapter, we take a quick look at sockets, and then turn our attention to examples that use them. You see how to send and receive mail. Sending mail is done using the Simple Mail Transfer Protocol (SMTP). Receiving mail is done using the Post Office Protocol (POP).


Sockets are the low-level links that enable Internet conversations and many other network services. There are a many functions that deal with sockets. Fortunately, you don't normally need to deal with them all. A small subset is all you need to get started. This section will focus in on those aspects of sockets that are useful in Perl. There will be whole areas of sockets that are not dealt with here.
A small selection of useful Perl socket functions is given below:
accept(NEWSOCKET, SOCKET)
-- Accepts a socket connection from clients waiting for a connection. The original socket, SOCKET, is left along, and a new socket is created for the remote process to talk with.SOCKET must have already been opened using the socket() function. Returns true if it succeeded, false otherwise.
bind(SOCKET, PACKED_ADDRESS)
-- Binds a network address to the socket handle. Returns true if it succeeded, false otherwise.
connect(SOCKET, PACKED_ADDRESS)
-- Attempts to connect to a socket. Returns true if it succeeded, false otherwise. getpeername(SOCKET)Returns the packed address of the remote side of the connection. This function can be used to reject connections for security reasons, if needed.
getsockname(SOCKET)
-- Returns the packed address of the local side of the connection.
getsockopt(SOCKET, LEVEL, OPTNAME)
-- Returns the socket option requested, or undefined if there is an error.
listen(SOCKET, QUEUESIZE)
-- Creates a queue for SOCKET with QUEUESIZE slots. Returns true if it succeeded, false otherwise.
recv(SOCKET, BUFFER, LEN, FLAGS)
-- Attempts to receive LENGTH bytes of data into a buffer from SOCKET. Returns the address of the sender, or the undefined value if there's an error. BUFFER will be grown or shrunk to the length actually read. However, you must initalize BUFFER before use. For example my($buffer) = '';.

select(RBITS, WBITS, EBITS, TIMEOUT)
-- Examines file descriptors to see if they are ready or if they have exception conditions pending.
send(SOCKET, BUFFER, FLAGS, [TO])
-- Sends a message to a socket. On unconnected sockets you must specify a destination (the TO parameter). Returns the number of characters sent, or the undefined value if there is an error.
setsockopt(SOCKET, LEVEL, OPTNAME, OPTVAL)
-- Sets the socket option requested. Returns undefined if there is an error. OPTVAL may be specified as undefined if you don't want to pass an argument.
shutdown(SOCKET, HOW)
-- Shuts down a socket connection in the manner indicated by HOW. If HOW = 0, all incoming information will be ignomiles. If HOW = 1, all outgoing information will be stopped. If HOW= 2, then both sending and receiving is disallowed.
socket(SOCKET, DOMAIN,TYPE, PROTOCOL)
-- Opens a specific TYPE of socket and attaches it to the name SOCKET. Returns true if successful, false if not.
socketpair(SOCK1, SOCK2, DOMAIN, TYPE, PROTO)
- Creates an unnamed pair of sockets in the specified domain, of the specified type. Returns true if successful, false if not.
Note
If you are interested in knowing everything about sockets, you need to get your hands on some UNIX documentation. The Perl set of socket functions are pretty much a duplication of those available using the C language under UNIX. Only the parameters are different because Perl data structures are handled differently. You can find UNIX documentation athttp://www.delorie.com/gnu/docs/ on the World Wide Web.

Clients and Servers

Programs that use sockets inherently use the client-server paradigm. One program creates a socket (the server) and another connects to it (the client). The next couple of sections will look at both server programs and client programs.

 The Server Side of a Conversation

Basic server communication is established as follows:
·                  Server programs will use the socket() function to create a socket;
·                  bind() to give the socket an address so that it can be found;
·                  listen() to see if anyone wants to talk; and
·                  accept() to start the conversation.
·                  Then send() and recv() functions can be used to hold the conversation.
·                  And finally, the socket is closed with the close() function.
The socket() call in Perlwill look something like this (basic_socket.p):
$tcpProtocolNumber = getprotobyname('tcp') || 6;
 
 
socket(SOCKET, PF_INET(), SOCK_STREAM(), $tcpProtocolNumber)
    || die("socket: $!");
The first line gets the TCP protocol number using the getprotobyname() function. Some systems (e.g. Windows 95) do not implement this function, so a default value of 6 is provided. Then, the socket is created with socket().
The socket name is SOCKET.
Notice that it looks just like a file handle. When creating your own sockets, the first parameter is the only thing that you should change. The rest of the function call will always use the same last three parameters shown above. The actual meaning of the three parameters is unimportant at this stage. If you are curious, please refer to the UNIX documentation previously mentioned.
Socket names exist in their own namespace. Actually, there are several pre-defined namespaces that you can use. The namespaces are called protocol families because the namespace controls how a socket connects to the world outside your process. For example, the PF_INET namespace used in the socket() function call above is used for the Internet.
Once the socket is created, you need to bind it to an address with the bind() function.
The bind() call might look like this (bind.pl):
$port = 20001;
$internetPackedAddress = pack('Sna4x8', AF_INET(), $port, "\0\0\0\0");
 
 
bind(SOCKET, $internetPackedAddress) 
    ||die("bind: $!");
All Internet sockets reside on a computer with symbolic names. The server's name in conjunction with a port number makes up a socket's address. For example, www.cs.cf.ac.uk:20001. Symbolic names also have a number equivalent known as the dotted decimal address. For example, 131.251.42.1. Port numbers are a way of determining which socket atwww.cs.cf.ac.uk you'd like to connect to. All port numbers below 1024 (or the symbolic constant, IPPORT_RESERVED) are reserved for special sockets. For example, port 37 is reserved for a time service and 25 is reserved for the smtp service. The value of 20,001 used in this example was picked at random. The only limitations are: use a value above 1024 and no two sockets on the same computer should have the same port number.
Remember: You can always refer to your own computer using the dotted decimal address of 127.0.0.1 or the symbolic name localhost.
The second line of this short example creates a full Internet socket address using the pack() function. This is another complicated topic that I will sidestep. As long as you know the port number and the server's address, you can simply plug those values into the example code and not worry about the rest. The important part of the example is the "\0\0\0\0" string. This string holds the four numbers that make up the dotted decimal Internet address. If you already know the dotted decimal address, convert each number to octal and replace the appropriate \0 in the string.
If you know the symbolic name of the server instead of the dotted decimal address, use the following line to create the packed Internet address:
$internetPackedAddress = pack('S n A4 x8', AF_INET(), $port, gethostbyname('www.remotehost.com'));
After the socket has been created and an address has been bound to it, you need to create a queue for the socket. This is done with the listen() function.
The listen() call looks like this:
listen(SOCKET, 5) || die("listen: $!");
This listen() statement will create a queue that can handle 5 remote attempts to connect. The sixth attempt will fail with an appropriate error code.
Now that the socket exists, has an address, and has a queue, your program is ready to begin a conversation using the accept() function. The accept() function makes a copy of the socket and starts a conversation with the new socket. The original socket is still available and able to accept connections. You can use the fork() function, in UNIX, to create child processes to handle multiple conversations. The normal accept() function call looks like this:
$addr = accept(NEWSOCKET, SOCKET) or die("accept: $!");
Now that the conversation has been started, use print(), send(), recv(), read(), or write() to hold the conversation. The examples later in the chapter show how the conversations are held.

 The Client Side of a Conversation

Basic clinet connection to a server is established as follows:
·                  Client programs will use socket() to create a socket and
·                  connect() to initiate a connection to a server's socket.
·                  Then input/output functions are used to hold a conversation.
·                  Finally the close() function closes the socket.
The socket() call for the client program is the same as that used in the server, client.pl:
$tcpProtocolNumber = getprotobyname('tcp') || 6;
socket(SOCKET, PF_INET(), SOCK_STREAM(), $tcpProtocolNumber)
    || die("socket: $!");
After the socket is created, the connect() function is called like this, connect.pl:
$port = 20001;
$internetPackedAddress = pack('Sna4x8', AF_INET(), $port, "\0\0\0\0");
 
 
connect(SOCKET, $internetPackedAddress) or die("connect: $!");
The packed address was explained in "The Server Side of a Conversation." The SOCKET parameter has no relation to the name used on the server machine. I use SOCKET on both sides for convenience.
The connect() function is a blocking function. This means that it will wait until the connection is completed. You can use the select() function to set non-blocking mode, but you'll need to look in the UNIX documentation to find out how. It's a bit complicated to explain here.
After the connection is made, you use the normal input/output functions or the send() and recv() functions to talk with the server.
The rest of the chapter will be devoted to looking at examples of specific protocols. Let's start out by looking at the time service.

No comments:

Post a Comment