Newsgroups: bit.listserv.ibmtcp-l
Date:         Tue, 7 Apr 1992 10:10:52 EDT
From:         Ron Lane <RONLANE@YKTVMV.BITNET>

Re:   Sockets and server programs
Ref:  Your note of Mon, 6 Apr 1992 10:07:48 BST (attached)

>The question  is how (if  at all) do  you use the  socket interface
>with a  server when you  (potentially) want multiple  clients.
>With the  Socket interface you appear  to be able to  call socket()
>many times to  create sockets but HOW (if at  all) do you 'connect'
>more than one of these sockets to  the port on which the client and
>server at to communicate.

The server does a bind on a port number/socket number, and then
does a listen (telling that it will be listening) and then a select
(saying wake me up when a client knocks on the door of this port).
When the server wakes up, it does an 'accept' that GIVES IT
A NEW SOCKET NUMBER TO TALK ON.  In other words, the first socket
the server gets is for the 'select'.  Then when it gets the new
socket number via the 'accept' (after being woken up from the
the 'select'), it spawn a task and hands over this new socket
number via the givesocket/takesocket operation.  Then the new
process/task is free to talk on this new socket, while the
parent does another select again, waiting for another client
to wake it up.

I'm appending to this note a description of this process that
will be part of an upcoming programmers guide.

Ron Lane
TCP/IP Development



 SOCKET PROGRAMMING
 __________________

We will begin by giving an introduction to socket programming for
those readers who don't already know it.  We will discribe a simple
client/server application with subtasking.  You'll see that a
sophisticated client/server dialogue can be accomplished with
just a few simple verbs. The verbs we will describe are:

Used by both Server and Client:
 socket - gets a socket number to read from or write to.
 send - sends data to the one receiving at the other end of a socket.
 recv - receives data from the other end of a socket connection.
 close - gives back a socket number when a user no longer needs it.

Used by Server:
 bind   - lets a server associate a socket with a port number.
 listen - tells TCP/IP that it will be listening on this socket.
 select - waits for activity on a socket.
 accept - gets a new socket to talk to a client that woke up select.

Used by Client:
 connect - lets a client open up a connection to a server port.

Used only for Subtasking:
 givesocket - gives a socket to a subtask.
 takesocket - accepts a socket from a parent task.
 getname - finds out what name TCP/IP internally refers to me by.

There are two types of sockets, stream and datagram.  Stream
sockets are far more common for the applications we are
discussing, so we won't even describe the difference, and you
can assume that all further discussion refers to stream sockets.

Every machine that communicates over a TCP/IP network must have
an 8 byte IP address.  These addresses are assigned by a world-wide
TCP/IP number giver, and each is unique.  Every machine also has
a Node Name associated with that number, and the translation from
Name to number and back again is done by a program known as a
Name Server.  Since most people find it easier to remember names
rather than numbers, they specify the Node Names of the machines
they want to talk to and let the Name Server translate it into the
IP address.

We'll begin this discussion from the vantage point of the server,
because it is the one who begins the activity.  It has some service
it wants to provide (such as access to data or mail) and it
must make it known that it is providing this service before people
can request that service from it.

The first task of the server is to get a number from 1 to 4096
that will be associated with this service it wants to provide.
This is called a Port Number.  Some well known servers, such
as FTP (File Transfer Protocol) or Telnet (let's you logon to
another machine) have well known port numbers (FTP's is always
port 21, for example).  So a server says:

"I am on machine with node number xxxxxxxx providing a service
on port yyyy'.

If a client wants to talk to FTP running on a node named FILESRV3,
it will refer to node name FILESRV3 in its FTP command, and then
under the covers a Name server finds out the IP number for
FILESRV3 by looking it up in its tables,
and then communicates to port 21 (always FTP's port number) on
the machine with that IP address.
In your own client/server applications, you will
need a method of assigning port numbers to represent the various
services you intend to provide.

 The Server Begins
 _________________

The first thing the server must do is get a socket.  It will use
this socket to listen for requests for its service.  It asks
TCP/IP for a socket number, who assigns it one.  Socket numbers are
usually assigned in ascending order, and the first few are
usually already taken, so it's not unusual to get, let's say,
socket 3 the first time through.  In C this request for a socket
looks like this:

         s = socket(AF_INET, SOCK_STREAM, 0);

It's a function call that passes some parameters (in this case it wants
a stream socket over the network) and is returned a value
's' that is the socket number.

 The Bind
 ________

The next thing the server does is ask TCP/IP to do a 'bind'.
This bind associates together three things in the 'mind' of TCP/IP:
 - the number of the port that the server wants to do this service on
 - the IP address of the machine the server is running on
 - the socket the server was just given.

In other words, it could say, "I want to handle requests for port 523,
I am at IP address 123.45.67.8, and please notify me of those requests
on my socket 3."

In C (just in case you are interested),
it puts the port number and IP address in a structure
called 'sockaddr_in' and then does a bind function giving both
the address of that structure and its socket number.

 The Listen
 __________

After the bind, it still has to notify TCP/IP that it now intends to
listen on this Port.  It does this (in C) by saying:

      listen(socket_number, backlog_number)

giving the socket number it will be listening on and the number of
requests that can be queued (known as the backlog_number).

 The Versatile Select
 ____________________

The Server is now ready to start handling requests on this port from
any client in the world that can address its node and port number.
This is done with probably the most important socket function,
called 'select'.  Select is THE function call for servers, and
allows the server to act like a juggler.  For every socket it wants to
handle (it can handle any number of sockets at once) it calls
a function to set a bit in a bit mask.

In C two of the functions that set this bit mask are:
 - FD_SET (to set the bit corresponding to a socket)
 - FD_ZERO (to clear the whole bit mask)

The server then specifies THREE bit masks in its Select function:
one for clients that want to send a message, another for clients
who want to receive a message,
and lastly any exceptional conditions. In other
words, it can tell TCP/IP:  "check the following sockets
for clients who want to send me anything or want me to send them
something, and tell me about any exeptional conditons."

Don't be daunted by the complexity of the Select function.  A
sophisticated server can be written that only wants to be woken
up for clients who want to write to it on ONE socket.

If there is nothing to be done, it can then go off and do other
work and later come back to the select again to check again for work.
But often the Server does a 'blocking select', that is it
tells TCP/IP "If there's nothing for me to do now as a result of this
Select, then let me go to sleep,
and wake me up when there are
any requests for activity on any of these sockets".  It can also
specify a timeout value, to be woken up after a certain amount of
time even if no request for activity occurs.

 The Accept
 __________

A positive return code coming back from the Select function means that
some client out there wants to talk to it (or there's an exceptional
condition to be handled, we'll cover an example of that later when
we discuss Givesocket).  So the server asks for another socket to
use to converse with this new client.  It does this with an 'accept'
function call.  It passes to the accept function the socket number
it was listening on, and the accept function passes back a new
socket number to conduct this new conversation on.

We want to emphasize that this is a new socket number, let's say
socket number 4 as opposed to the socket it does it's listening
on, let's say socket 3.  This new socket number is then used to
communicate back and forth with the client that requested this
new conversation.  The server can have many conversations
going on at the same time, and each conversation begins the
same way. A client requests the conversation, the server gets
notified of this request after it does a select.  Then the server
does an accept to get a new socket number for the conversation to
be held on.  Now 'sends' and 'receives' can be done with the
the client on this new socket.

 The Client's Perspective
 ________________________

The Client has a much easier job to do.  First it does a
'socket' function call to get a socket number to talk on (this is
assigned by the TCP/IP of the machine it resides on).

Then it says that it wants to start a conversation with a specific
server out there.  It does this by giving the IP address of the machine
the server is on, and the Port number that the server is listening on.

Often a client doesn't know the exact IP address of the server
machine, but only the nodename, such as PRTSERVE.  So it can
ask TCP/IP to use the nameserver to return the IP address that this
nodename (for example, PRTSERVE) is currently residing on.

 The Conversation
 ________________

The actual conversation is easy.  The client and server now
alternatively 'send' and 'recv' messages back and forth to each other.
The 'send' function call merely specfies a socket number to use,
(for the server, this is the socket number returned from the accept,
and for the client this is the socket number it has gotten to do all
conversations on), along with the address of a message and the
length of that message.  As in all conversations (machine and
human) it's important to be listening when the other side wants
to talk, and to talk when the other side is waiting for you to say
something.

Then when the conversation is over, and a socket is no longer
needed, the socket number is returned to the TCP/IP for that
machine with the 'close' function call.

 Givesocket/ Takesocket
 ______________________

A server is like a dispatcher at a messenger service.  A messenger
dispatcher gets phone calls from people who want items
delivered and the dispatcher sends out messengers to run around the
city to do the work.  Though the messenger dispatcher receives
and coordinates the requests, he gets others to actually carry out
the work.

In a similar manner, our server receives the requests, and then
spawns tasks to actually carry them out.  In Unix this is done
with a 'fork' call, that starts up an independent process to
carry out the request.  In MVS, this is done with an ATTACH to
start an independent task.

When the server gets notified as a result of its select that
a client wants to talk to it, it then does an accept that gives it
a new socket number for this new conversation.  At this point
the server can
do an ATTACH of a subtask to handle this new conversation, or it
can do a bunch of ATTACHes when it first starts up and dole out
the work that comes in to tasks that already exist.

In either case, it has to give this new socket (acquired via the
accept) to the subtask that will be assigned this new conversation.
You might think all it has to do is pass the socket number to
the subtask.
Alas, it's not that simple, because each task has its own
socket numbers.

For example, socket number 4 for task A is not the same
as socket number 4 for task B.  A socket is like a telephone line
reserved for communication, and each task has its own table of
sockets.  The number of the socket, let's say 4, is merely the
index into its own table, and the fourth entry in task A's table of
sockets does not refer to the same real socket as the fourth
entry in task B's table.

Be that as it may, a facility has been set up for the server to
give the socket that it has gotten for this new conversation to
another task to use to conduct this conversation.  This is done by
the main server task doing a Givesocket, and the subtask acquiring
the socket with a Takesocket.

 Doing the Givesocket/ Takesocket
 ________________________________

For C programs using  MVS TCP/IP,
each task has its own unique 8 byte name, that is actually based on
an EBCDIC version of its TCB address.  A task finds out its
name with a 'getname' function call.  The main server task passes
three pieces of information in its Givesocket call:
 - the socket number it wants to give
 - its own name
 - the name of the task it want to give the socket to.

The socket number was acquired when it did the accept.  It learns
its name by doing a getname.  The trick is that it blanks out
the name of the task it want to give the socket to, thereby
saying 'give this socket to the first task that asks for a socket
from me'.

Another trick is that it has to pass this information to the
subtask before the subtask can do a Takesocket. The subtask must
be notified (perhaps via a common workarea and posting an ECB to
wake the subtask up) about the number of the parent's socket it is to
acquire and its parent task's name.

The subtask, after it is woken up, takes this information, and
does a Takesocket. The Takesocket function assigns a
new socket number that the subtask can use. This represents
the same line of communication as the socket that the parent gave it.
The transferred socket may be referred to as socket number 4 by
the parent task, and be referred to by the subtask, for example, as
ITS socket number 3.  But from the vantage point of TCP/IP
its the same real socket.

The subtask can now go about using this socket that he's
acquired via the takesocket, by doing SEND's and RECV's over it.

The parent (the main server task) must do one extra bit of
cleanup activity.  It has to close the socket it has just given.
But it first has to wait for notification that the Givesocket has
been successful.  Strange as it may seem, it does this with
a Select, and waits for an exceptional condition on the socket
it just gave.  When it wakes up, indicating that the givesocket
has worked, it then closes the socket it just gave.  It can now go
back to handling requests for communications from clients
'out there.'
Comments: Gated by NETNEWS@AUVM.AMERICAN.EDU