Tutorial 10
In this tutorial, we are going to familiarize ourselves with inter-process
communication by sockets. We will have some hands-on experience with ready to
use C programs. Use Vi, Emacs or Pico for editing the files. Login to one of the
following pcs:
cs1.utdallas.edu
cs2.utdallas.edu
Use PuTTY or Xmanager for logging on as you learnt in
Tutorial 1.
Socket programming
A socket is an interface between an application and the network. The application creates a socket. The socket type dictates the style of communication. Socket types can be reliable vs. best effort or connection-oriented vs. connectionless. Once configured, the application can pass data to the socket for network transmission and receive data from the socket (transmitted through the network by some other host).
There are two essential type of sockets:
SOCK_STREAM
TCP sockets
reliable delivery
in-order guaranteed
connection-oriented
bidirectional

SOCK_DGRAM
UDP sockets
unreliable delivery
no order guarantees
no notion of “connection”
can send or receive

Creating a TCP socket in C requires calling a fixed set of functions in a fixed sequence. The following image illustrates it:
A socket is created by calling the C
API socket.
pint s = socket(domain, type, protocol);
s: socket descriptor, an integer (like a
file-handle)
type: communication type
SOCK_STREAM: reliable, 2-way, connection-based service
SOCK_DGRAM: unreliable, connectionless,
protocol:
The protocol specifies a particular protocol to be used with the socket.
Normally only a single protocol exists to support a particular socket type
within a given protocol family, in which case protocol can be specified as 0. As
there is only one protocol associated with SOCK_STREAM and SOCK_DGRAM, we will
use 0.
|
int hSocket; /* handle to socket */ |
To understand addresses, ports and socket and how they fit together, we can think on an analogy:
pLike apartments and mailboxes
You are the application
Street address of your apartment building is the IP address
Your mailbox is the port
The post-office is the network
The socket is the key that gives you access to the right mailbox
pint status = bind(sockid, &addrport, size);
status: error status, = -1 if bind failed
sockid: integer, socket descriptor
addrport: struct sockaddr, the (IP) address and port of the machine (address usually set to INADDR_ANY chooses a local address)
size: the size (in bytes) of the addrport structure
The addrport is a structure of type "sockaddr". This structure holds the information of the IP address and port. It is described below for internet-specific use:
Here is a sample server code below, it has code up to the bind call:
|
int hServerSocket; /* handle to socket */ |
A connection occurs between two kinds of participants:
passive: waits for an active participant to request connection
active: initiates connection request to passive side
Once connection is established, passive and active participants are “similar”:
both can send & receive data
either can terminate the connection
Passive
participant (Server)
step 1: listen (for incoming requests)
step 3: accept (a request)step 4: data transfer
The accepted connection is on a new socket
The old socket continues to listen for other active participants

Active participant (Client)
step 2: request & establish connection
step 4: data transfer
Following are the functions called by the server to
establish connection:
int status = listen(sock, queuelen);
status: 0 if listening, -1 if error
sock: integer, socket descriptor
queuelen: integer, # of active participants that can “wait” for a connection
listen is non-blocking: returns immediately
int s = accept(sock, &name,
&namelen);
s: integer, the new socket (used for data-transfer)
sock: integer, the orig. socket (being listened on)
name: struct sockaddr, address of the active participant
namelen: sizeof(name): value/result parameter
accept is blocking: waits for connection before returning
Note that accept returns a new socket for each connection
with client. So, at any time, the server will have one socket for listening to
connection requests and for each connection with client created, there will be
one new socket.
The corresponding code in our example is:
|
#include <sys/socket.h> |
The function called by the client to establish connection
is the following:
int status = connect(sock, &name, namelen);
status: 0 if successful connect, -1 otherwise
sock: integer, socket to be used in connection
name: struct sockaddr: address of passive participant
namelen: integer, sizeof(name)
connect is blocking
To write a client code, we will also need a structure
called "hostent":
struct hostent
This data type is used to represent an entry in the hosts database. It has the following members:
char *h_name
This is the "official" name of the host.
char **h_aliases
These are alternative names for the host, represented as a null-terminated vector of strings.
int h_addrtype
This is the host address type; in practice, its value is always either AF_INET or AF_INET6, with the latter being used for IPv6 hosts. In principle other kinds of addresses could be represented in the database as well as Internet addresses; if this were done, you might find a value in this field other than AF_INET or AF_INET6.
int h_length
This is the length, in bytes, of each address.
char **h_addr_list
This is the vector of addresses for the host. (The host might be connected to multiple networks and have different addresses on each one.) The vector is terminated by a null pointer.
char *h_addr
This is a synonym for h_addr_list[0]; in other words, it is the first host address.
We will use the following function to populate the
structure:
struct hostent * gethostbyname (const char *name)
The gethostbyname function returns information about the host named name. If the lookup fails, it returns a null pointer.
Here is an example client code up to connect call:
|
int hSocket; /* handle to socket */ |
After establishing connection, data transfer starts with
it. Transfer is done by the following two functions:
int count = write(sock, &buf, len);
count: # bytes transmitted (-1 if error)
buf: char[], buffer to be transmitted
len: integer, length of buffer (in bytes) to transmit
int count = read(sock, &buf, len);
count: # bytes received (-1 if error)
buf: void[], stores received bytes
len: # bytes received
Calls are blocking [returns only after data is sent (to socket buf) / received]
After communication is done, one should close connection by
the following API:
status = close(s);
status: 0 if successful, -1 if error
s: the file descriptor (socket being closed)
Closing a socket
closes a connection (for SOCK_STREAM)
frees up the port used by the socket
A complete example
Here is a complete example for a server and a client. The client connects to the
server, taking input from user it sends a sequence number to server for which it
wants to know the Fibonacci number, the server calculates and replies back.
Client then prints the number to the terminal. Once started, server enters an
infinite loop and replies to clients requests and waits for another client. To
stop the server Ctrl + C needs to be pressed. First is the server code:
|
// server.c |
Here is the client code:
|
// client.c |
Save the server as server.c and client as client.c. Compile them with the following commands:
{cs1:~/} gcc -o server server.c -lsocket -lnsl
{cs1:~/} gcc -o client client.c -lsocket -lnsl
Open a new terminal to run the server on cs2.utdallas.edu (or the client). Run the server:
{cs2:~/} ./server 4444
Starting server
Making socket
Binding to port 4444
opened socket as fd (3) on port (4444) for stream i/o
Server
sin_family = 2
sin_addr.s_addr = 0
sin_port = 4444
Making a listen queue of 1 elements
Waiting for a connection
Run the client:
{cs1:~/TA/PrinciplesOfUnix/Tutorials/Tutorial5} ./client cs1.utdallas.edu
4444
Making a socket
Connecting to cs1.utdallas.edu on port 4444
Which fibonacci number you need to know? 10
Fibonacci 10: 55
Closing socket
After giving the input "10", server's printout will be like this:
Waiting for a connection
Connected to 129.110.97.29:57739
Closing the socket
Waiting for a connection
You can run the client few more times if you wish. To close the server press Ctrl + C.