0% found this document useful (0 votes)
92 views38 pages

Understanding inet_ntoa in Sockets

Module 2 covers network programming concepts, focusing on socket programming including socket address structures, TCP socket functions, and address conversion functions. It explains the client-server model, the importance of byte ordering, and provides details on various socket functions like bind, connect, and accept. Additionally, it discusses the differences between IPv4 and IPv6, as well as the handling of variable length socket address structures.

Uploaded by

Afreed Shahid
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
92 views38 pages

Understanding inet_ntoa in Sockets

Module 2 covers network programming concepts, focusing on socket programming including socket address structures, TCP socket functions, and address conversion functions. It explains the client-server model, the importance of byte ordering, and provides details on various socket functions like bind, connect, and accept. Additionally, it discusses the differences between IPv4 and IPv6, as well as the handling of variable length socket address structures.

Uploaded by

Afreed Shahid
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Module-2 Network Programming

Module -2
Sockets Introduction – socket address structures, value-result arguments, byte ordering and
manipulation functions, address conversion functions, Elementary TCP Sockets – socket,
connect, bind, listen, accept, fork and concurrent server design, getcsockname and
getpeername functions and TCP Client/Server Example.
Sockets Introduction
Most network application can be divided into two programs: client and server with the
communication link between them as shown:

Examples are: A web browser communicating with a web server. A FTP client fetching a
file form an FTP server etc. A client normally communicates with a server at a time.
However, a server is likely to communicate with multiple client. The client and server
communication with in the same Ethernet and the communication when LAN connected
through WAN is shown below.

Dept of CSE 1
Module-2 Network Programming

As seen in above figure, TCP and IP protocols are normally part of the protocol stack within
the kernel. In addition to TCP and IP, other protocol like UDP is also used. IP that was in
use since early 1980 is called as IP version 4 (Ipv4). A new version IP version 6 (Ipv6) is
being used since mid-1990.
Socket Address Structure SAS:
This SAS is between application and kernal. An address conversion function translates
between text representation of an address and binary value that makes up SAS. IPv4 uses
inet_addr and inet_ntoa. But inet_pton and inet_ntop handle IPv4 and IPv6. Above
functiuons are protocol dependent. However the functions starting with sock are protocol
independent. Most socket functions require a pointer to a socket address structure as an
argument.
IPv4 Socket AS: It is defined as follows:
# include <netinet / in.h>

sin_len, added in 4.3 BSD, is not normally supported by many vendors. It facilitates
handling of variable length socket address structures.
Various data types that are commonly used are listed below:

Dept of CSE 2
Module-2 Network Programming

Length field is never used and set. It is used within the kernal before routines that deal
with socket address structures from various protocol families.
Four socket functions – bind(), connect(), sendto(), sendmsg() -pass socket address
structures from application to kernal. All invoke sockargs() in Berkley derived
implementation. This function copies socket address structures and explicitly set
the sin_len member to the size of the structure that was passed. The other socket functions
that pass socket address to the application from kernal accept(), recvfrom(), recvmsg(),
getpeername() and getsockname() all set the sin_len member before returning to the
process.
sin_port, sin_family and sin_addr are the only required for
Posix.1g. sin_zero is implemented to keep the structure length to 16 byte.
Generic Socket Address Structure.
Socket address structures are always passed by reference when passed as an arguments to
any of the socket functions.
int bind (int sockfd, struct sockaddr *, socklen_t);
But the socket function that accept these address structures as pointers must deal with any
of these supported protocols. This calls for the any functions must cast the pointer to the
protocol specific socket address structure to be a pointer to a generic socket address
structure. For example
struct sockaddr_in serv;
bind (sockfd, (struct sockaddr *) &serv, sizeof(serv));
If we omit the cast, the C compiler generates a warning of the form incompatible pointer
type.
Different socket address structures are :

Dept of CSE 3
Module-2 Network Programming

IPv4 (24 bytes), IPv6 (24 bytes), Unix variable length and Data link variable length.
IPv6 SAS:
Defined by # include<netinet/in.h> header. The structure is shown below:

Important points to note are:


• The SIN_LEN constant must be defined if the system supports the length
members for socket address structures.

The IPv6 family is AF_INET6


The members in this structure are ordered so that if the sockaddr_in6 structure is 64 bit
aligned, so is the 128 bit sin6_addr member.

• The sin6_flowinfo member is divided into three fields o The low order 24 bits are the
flow label

o The next 4 bits are the priority o The next 4 bits are reserved.

Dept of CSE 4
Module-2 Network Programming

Comparison of socket address structure:


Following figure shows the comparison of the four socket address structures that are
encountered.

Value Result Arguments


The socket address structure is passed to any of the socket function by reference. The
length of the structure is also passed as argument to the function. But the way the length is
passed depends on which direction it is being passed. From the process to the kernal or
kernal to the process.
1. The three functions bind(), connect() and sendto() pass a socket address
structure from the process to the kernal. One argument to these three function is
the pointer to the socket address structure and another argument is the integer
size of the structure.

struct sockaddr_in serv;


connect (sockfd, (SA *) & serv, sizeof(serv));

Dept of CSE 5
Module-2 Network Programming

Since the kernal is passed both pointer and the size of what the pointer points to, it knows
exactly how much data to copy from the process into the kernal. Following figures shows
this scenario:

The four functions accept(), recvmsg(), getsockname() and getpeername() pass a socket
address structure from kernal to the process, the reverse direction form the precious
scenario. In this case the length is passed as pointer to an integer containing the size of
structure as in
struct sockaddr_un cli; // Unix domain// socklen_t len;
len = sizeof (cli);
getpeername (unixfd, (SA *) &cli, & len );
The reason that the size changes from an integer to be a pointer to an integer is because
the size is both value when the function is called ( it tells the kernal the size of the structure
so that the kernal does not write past the end of the4 structure when filling it ) and it is
the result when the function results (It tells the process how much information the kernal
actually stored in the structure). This type of argument is called value – result arguments.

Dept of CSE 6
Module-2 Network Programming

With variable length socket address structure, the value returned can be less than the
maximum size of the structure.
Byte Order functions
There are two ways to store the 2 bytes in the memory. With the low order byte at the
starting address known little endian byte order a or with high order byte at the starting
address known as big endian byte order.

The terms little endian or big endian indicate which end of the multi byte value , the
little end or the big end is stored at the starting address of the value. Different systems
use different orderings. For example, PowerPC of IB, sparc of Sun Soloaris, Happal of HP
all use big endian while i386 PC of BSDi and i586 pc of Linux use little endian. The byte

Dept of CSE 7
Module-2 Network Programming

order used by a given system is known as the host byte order. As network programmer,
one need to deal with the different byte orders. That is the sending and receiving protocol
stack must agree on the order in which the bytes of these multibyte fields are transmitted.
Internet protocol uses big endian byte ordering for these multibyte system.

Normally, the address structure may be maintained in the host byte order system. Then it
may be converted into network byte order as per requirement. However, Posix.1g specifies
that the certain files in socket address structure be maintained in network byte order .
Therefore, there are function that convert between these two byte orders.

# include <netinet/in.h>

uint16_t htons(uint16_t host16bitvalue);


uint32_t htons(uint32_t host32bitvalue);
Return value in network byte order.
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohs(uint32_t net16bitvalue);
Returns value in host byte order.

Appropriate function are called to convert a given value between the host and network byte
order. On those systems that have the same byte order as the Internet protocols (big endian),
these four functions are usually defined as null macros.

Byte manipulation functions


There are two groups of functions that operate on multi byte fields, without interpreting
the data, and without assuming that the data is a null terminated C string. We need these
types of functions when dealing with sockets address structures as we need to manipulate
fields such as IP addresses which can contain byte of 0, but these fields are not character
strings. The functions beginning with str ( for string), defined by including the < string.h>
header, deal with null terminated C character strings.

Dept of CSE 8
Module-2 Network Programming

The first group of functions whose name begin with b (for byte) are from 4.3. BSD.
The second group of functions whose name begin with mem ( for memory) are from ANSI
C library.
First Berkeley derived functions are shown.
# include <strings.h>
void bzero ( void *dest, size_t nbytes);
void bcpy (const void *src, void * dest, size_t nbytes);
int bcmp ( cost void * ptr1, const void *ptr2, size_t nbytes)
constant qualifier indicates that the pointer with this qualification, src, ptr1, ptr2 are not
modified by the function.. That is memory pointed to by the cost pointer is read but not
modified by the function.
bzero ( ) sets the specified number of bytes to 0 in the destination. This function is
often used to initialize a socket address structure to 0. bcopy ( ) moves the specified
number of bytes from the source to the destination. bcmp ( ) compares two arbitrary byte
strings . The return value is zero if the two byte strings are identical; otherwise it is nonzero.
Following are the ANSI C functions:
# include <strings.h>
void memset ( void *dest, int c, size_t len);
void memcpy (void *dest, const void * src, size_t nbytes); int memcmp ( const
void * ptr1, const void *ptr2, size_t
nbytes); Returns 0 if equal, <0 or >0 if unequal.
memset () sets the specified number of bytes to the value in c in the
destination, memcpy() is similar to bcopy () but the order of the two pointer arguments is
swapped. bcopy correctly handles overlapping fields, while the behaviour of memcpy() is
undefined if the source and destination overlap. memmove() functions can be used when
the fields overlap. memcpy() compares two arbitrary byte strings and returns 0 if they are
identical, if not, the return value is either greater than 0 or less than 0 depending whether
the first unequal byte pointed to by ptr1 is greater than or less than the corresponding byte
pointed to by ptr 2.
Address conversion functions: There are two groups of address conversion function that
convert the Internet address between ASCII strings (readable form) to network byte
ordered binary values and vice versa.

Dept of CSE 9
Module-2 Network Programming

inet_aton( ), inet_addr( ), and inet_ntoa( ) : convert an IPv4 address between a dotted


decimal string (eg [Link]) and it s 32 bit network byte ordered binary values
#include <arpa/inet.h>
int inet_aton (const * strptr, strut in_addr * addptr);
The first of these, inet_aton( ) converts the C character strings pointed to by the strptr
into its 32 bit binary network byte ordered value which is stored through the
pointer addptr. If successful 1 is returned otherwise a 0.
in_addr_t inet_addr (const char * strptr);
inet_addr( ) does the same conversion, returning the 32 bit binary network byte ordered
value as the return value. Although the IP address ([Link] through [Link]) are
al valid addresses, the functions returns the constant INADDR_NONE on an error.
This is deprecated and the new code should use inet_aton instead.
The function inet_ntoa ( ) function converts a 32 bit binary network byte ordered IPv4
address into its corresponding dotted decimal string. The string pointed to by the return
value of the function resides in static memory. This functions structure as arguments, not
a pointer to a structure. (This is rare)
inet_pton ( ) and inet_ntop( ) functions:
These two functions are new with the IPv6 and work with both IPv4 and IPv6 addresses.
The letter p and n stands for presentation and numeric. Presentation format for an
address is often ASCII string and the numeric format is the binary value that goes into a
socket address structure.
# include <arpa/inet.h>
int inet_pton (int family, const char *strptr, void *addrptr);
const char *inet_ntop (int family, cost void *addrptr, char *strptr, size_t len);
The family argument for both function is either AF-INET or AF_ INET6. If
family is not supported, both functions return –1 with errno set to EAFNOSUPPORT.
The first functions tries to convert the string pointed to by strptr, storing the binary
results through the pointer addrptr. IF successful, the return value is 1. If the input string
is not valid presentation format for the specified family, 0 is returned.
inet_pton () does the reverse conversion from numeric (addrptr) to presentation
(strptr). The len argument is the size of the destination, to prevent the function from

Dept of CSE 10
Module-2 Network Programming

overflowing the caller‘s buffer. To help specify this size, following two definitions are
defined by including the
<netinet/in.h> header:

#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
If LEN is too small to hold the resulting presentation format including the terminating
null, a null pointer is returned and errno is set ot ENOSPC.
The strptr argument to inet_ntop cannot be a null pointer. The caller must allocate
memory for the destination and specify its size. On success this pointer is the return value
of the function.
This is summarized in the following figure.
Elementary TCP Sockets
Socket calls are those functions that provide access to the underlying functionality and
utility routines that help the programmer. A socket can be used by client or by a server,
for a stream transfer (TCP) or datagram (UDP) communication with a specific endpoints
address.
Following figure shows a time line of the typical scenario that takes place between client
and server.

Dept of CSE 11
Module-2 Network Programming

First server is started, then sometimes later a client is started that connects to the
server. The client sends a request to the server, the server processes the request, and the
server sends back reply to the client. This continues until the client closes its end of the
connection, which sends an end of file notification to the server. The server then closes
its end of the connections and either terminates or waits for a new connection.
socket function:
#include socket (int family, int type, int protocol);
returns negative descriptor if OK & –1 on error.
Arguments specify the protocol family and the protocol or type of service it needs (stream
or datagram). The protocol argument is set to 0 except for raw sockets.

Dept of CSE 12
Module-2 Network Programming

Not all combinations of socket family and type are valid. Following figure shows the valid
combination.

connect Function: The connect function is by a TCP client to establish an


active connection with a remote server. The arguments allow the client to specify the
remote end points which includes the remote machines IP address and protocol port
number.
# include <sys/socket.h>
int connect (int sockfd, const struct sockaddr * servaddr, socklen_t addrelen)
returns 0 if ok -1 on error.
sockfd is the socket descriptor that was returned by the socket function. The second and
third arguments are a pointer to a socket address structure and its size.
In case of TCP socket, the connect() function initiates TCP’s three way
handshake. The function returns only when the connection is established or an error
occurs. Different type of errors are :
1. If the client TCP receives no response to its SYN segment, ETIMEDOUT is
returned. This is done after the SYN is sent after, 6sec, 24sec and if no
response is received after a total period of 75 seconds, the error is returned.

2. In case for SYN request, a RST is returned (hard error), this indicates that no
process is waiting for connection on the server. In this
case ECONNREFUSED is returned to the client as soon the RST is received.
RST is received when (a) a SYN arrives for a port that has no listening server

Dept of CSE 13
Module-2 Network Programming

(b) when TCP wants to abort an existing connection, (c) when TCP receives a
segment for a connection does not exist.
3. If the SYN elicits an ICMP destination is unreachable from some
intermediate router, this is considered a soft error. The client server saves the
message but keeps sending SYN for the time period of 75 seconds. If no
response is received, ICMP error is returned as
EHOSTUNREACH or ENETUNREACH.
In terms of the TCP state transition diagram, connect() moves from the
CLOSED state to the SYN_SENT state and then on success to the
ESTABLISHED state. If the connect fails, the socket is no longer usable and must
be closed.
Bind(): When a socket is created, it does not have any notion of end points
addresses An application calls bind to specify the local endpoint address for a
socket. That is the bind function assigns a local port and address to a socket..
#include <sys/socket.h>
int bind (int sockfd, const strut sockaddr *myaddr, socklen_t addrlen)

The second arguments is a pointer to a protocol specific address and the third
argument is the size of this address structure. Server bind their well known port when they
start. (A TCP client does not bind an IP address to its socket.)
listen Function:
The listen function is called only by TCP server and it performs following
functions.
The listen function converts an unconnected socket into a passive socket, indicating
that the kernel should accept incoming connection requests directed to this socket. In
terms of TCP transmission diagram the call to listen moves the socket from
the CLOSED state to the LISTEN state.
The second argument to this function specifies the maximum number of
connections that the kernel should queue for this socket.
#include <sys/socket.h>
int listen (int sockfd, int backlog); returns 0 if OK -1 on error.
This function is normally called after both the socket and bind functions and must be
called before calling the accept function.

Dept of CSE 14
Module-2 Network Programming

The kernel maintains two queues and the backlog is the sum of these two queues. These
are :
An incomplete connection queue, which contains an entry for each SYN that has
arrived from a client for which the server is awaiting completion of the TCP three
way handshake. These sockets are in the SYN_RECD state.
A Completed Connection Queue which contains an entry for each client with whom
three handshake has completed. These sockets are in the ESTABLISHED state.
Following figure depicts these two queues for a given listening socket.

The two queues maintained by TCP for a listening socket.

When a SYN arrives from a client, TCP creates a new entry on the incomplete queue and
then responds with the second segment of the three way handshake. The server ‘s SYN
with an ACK of the clients SYN. This entry will remain on the incomplete queue until the
third segment of the three way handshake arrives ( the client‘s ACK of the server‘s SYN)
or the entry times out. If the three way hand shake completes normally, the entry moves
from the incomplete queue to the completed queue. When the process calls accept, the
first entry on the completed queue is returned to the process or, if the queue is empty, the
process is put to sleep until an entry is placed onto the completed queue. If the queue are
full when a client arrives, TCP ignores the arriving SYN, it does not send an RST. This is
because the condition is considered temporary and the client TCP will retransmit its SYN
with the hope of finding room in the queue.

Dept of CSE 15
Module-2 Network Programming

accept Function : accept is called by a TCP server to return the next completed
connection from the from of the completed connection queue. If the completed queue is
empty, the process is put to sleep.

# include <sys/socket.h>
int accept ( sockfd, struct sockaddr * cliaddr, socklen_t *addrlen) ;
return non negative descriptor if OK, -1 on error.

The cliaddr and addrlen arguments are used to return the protocol address of the
connected peer process (the client). addrlen is a value-result argument before the call, we
set the integer value pointed to by *addrlen to the size of the socket address structure
pointed to by cliaddr and on return this integer value contains the actual number of bytes
stored by the kernel in the socket address structure. If accept is successful, its return value
is a brand new descriptor that was automatically created by the kernel. This new descriptor
refers to the TCP connection with the client. When discussing accept we call the first
argument to accept the listening and we call the return value from a accept the connected
socket
fork function:
fork is the function that enables the Unix to create a new process

#inlcude <unistd.h>
pid_t fork (void); Returns 0 in child, process ID of child in parent, -1 on error
There are two typical uses of fork function:

1. A process makes a copy of itself so that one copy can handle one operation while
the other copy does another task. This is normal way of working in a network
servers.

2. A process wants to execute another program. Since the only way to create a
new process is by calling fork, the process first calls fork to make a copy of
itself, and then one of the copies(typically the child process) calls exec function

Dept of CSE 16
Module-2 Network Programming

to replace itself with a the new program. This is typical for program such as
shells.

3. fork function although called once, it returns twice. It returns once in the
calling process (called the parent) with a return value that is process ID of the
newly created process (the child). It also returns once in the child, with a return
value of 0. Hence the return value
tells the process whether it is the parent or the child.

4. The reason fork returns 0 in the child, instead of parent‘s process ID is because
a child has only one parent and it can always obtain the parent‘s process ID by
calling getppid A parent, on the other hand, can have any number of children,
and there is no way to obtain

the process Ids of its children. If the parent wants to keep track of the process
Ids of all its children, it must record the return values form fork.
exec function :
The only way in which an executable program file on disk is executed by Unix is for an
existing process to call one of the six exec functions. exec replaces the current process
image with the new program file and this new program normally starts at the main
function. The process ID does not change. The process that calls the exec is the calling
process and the newly executed program as the new program.
The differences in the six exec functions are:
a. whether the program file to execute is specified by a file name or a pathname.
b. Whether the arguments to the new program are listed one by one or reference
through an array of pointers, and
c. Whether the environment of the calling process is passed to the new program
or whether a new environment is specified.
#include <unistd.h>
int execl (const char *pathname, const char arg 0, …/ (char *) 0 */); int execv
(const char *pathname, char *const argv[ ]);

Dept of CSE 17
Module-2 Network Programming

int execle (const char *pathname, const char *arg 0, ./ * (char *)0,char *const
envp[] */); int execve (const char *pathname, char *const arg [], char *const
envp[]);

int execlp (const char *filename, const char arg 0, …/ (char *) 0 */); int execvp
(const char *filename, char *const argv[]);

These functions return to the caller only if an error occurs. Otherwise control passes
to the start of the new program, normally the main function.

The relationship among these six functions is shown in the following figure
. Normally only execve is a system call within the kernal and the other five are
library functions that call execve.

1. The three functions in the top row specify each argument string as a separate
argument to the exec function, with a null pointer terminating the variable number
of arguments. The three functions in the second row have an argv array containing
the pointers to the argument strings. This argv array must contain a null pointer to
specify its end, since a count is not specified.

1. The two functions in the left column specify a filename argument. This is
converted into a pathname using current PATH environment variable. IF
the execlp (file, arg,.., 0)
2. filename argument to execlp or execvp contains a slash (/) anywhaere in the
string, the PATH variable is not used. The four functions in the right two columns
specify a fully qualified pathname arguments.

Dept of CSE 18
Module-2 Network Programming

3. The four functions in the left two column do no specify an explicit environment
pointer. Instead the current value of the external variable environ is used for
building an environment list that is passed to the new program. The two functions
in the right column specify an explicit environment list. The envp array of pointers
must be terminated by a null pointer.
concurrent server design
A server that handles a simple program such as daytime server is a iterative server. But
when the client request can take longer to service, the server should not be tied upto a single
client.
The server must be capable of handling multiple clients at the same time. The simplest way
to write a concurrent server under Unix is to fork a child process to handle each client.
Following program shows the typical concurrent server.
pid_t pid;
int listenfd, connfd;
listfd = socket ( , , , ); /*fill in sockaddr_in with server’s well known port*/ bind
(listenfd, …);
listen (listenfd, LISTENQ);
for ( ; ; ) {
connfd = accept (listenfd, …); if ( (pid = fork())== 0) {

close (listenfd); /* child closed listening socket */ doit


(connfd); /* process the request */

close ( connfd); /* done with the client*/ exit (0); /* child


terminates*/

}
close (connfd); /* parent closes connected socket*/
}

Dept of CSE 19
Module-2 Network Programming

When a connection is established , accept returns, the server calls fork, and
then the child process services the client ( on connfd, the connected socket ) and
the parent process waits for another connection ( on listenfd, the listening socket ).
The parent closes the connected socket since the child handles this new client.
In the above program, the function doit does whatever is required to service the client.
When this functions returns, we explicitly close the connected socket in the child. This is
not required since the next statement calls exit, and part of process termination is closing
all open descriptors by the kernal. Whether to include this explicit call to close or not is a
matter of personal programming taste.
The connection scene in case of concurrent server is shown below:

Dept of CSE 20
Module-2 Network Programming

close() The normal Unix close() is also used to close a socket and terminate a TCP
connection.
#include<unistd.h>
int close (int sockfd);
The default action of close with a TCP socket is to mark the socket as closed and
return to the process immediately. The socket descriptor is no longer usable by the
process. Thst is , it can not be used as an argument to read or write.
getsockname () and getpeername():

Dept of CSE 21
Module-2 Network Programming

These two functions return either the local protocol address associated with a socket
or the foreign address associated with a socket.
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localadddr, socklen_t
*addlen);
int getpeername(int sockfd, struct sockaddr *peeradddr, socklen_t
*addlen); both return 0 if OK and –1 on error.
These functions are required for the following reasons.
a. After connect successfully returns a TCP client that does not call bind(),
getsocketname() returns the local IP address and local port number assigned to the
connection by the kernel

b. After calling bind with a port number of 0, getsockname() returns the local port
number that was assigned

c. When the server is exceed by the process that calls accept(), the only way the
server can obtain the identity of the client is to call getpeername().

TCP Client/Server Example


1. Client – Server communication involves reading of text ( character or text) from the
client and writing the same into the server and server reading text and client writing the
same. Following picture depicts the same.

Functions fgets() and fputs() are from standard I/O library. And writen() and
readline() are function created by the W Richard Stevans (WRS) (code given in the
section 3.9)

Dept of CSE 22
Module-2 Network Programming

The communication between client and server is understood by Echo client and Server.
The Following code corresponds to Server side program.

Line 1: It is the header created by the WRS which encapsulates a large number of header
that are required for the functions that are referred.
Line 2 – 3: This the definition of the main() with command line arguments. Line 5-8 :
These are variable declarations of types that are used.

Line 9 : It is the system call to the socket function that returns a descriptor of type int.- in
this case it is named as listenfd. The arguments are family type, stream type and protocol
argument – normally 0)
Line 10: the function bzero() sets the address space to zero.

Dept of CSE 23
Module-2 Network Programming

Line 11-12: Sets the internet socket address to wild card address and the server port to the
number defined in SERV_PORT which is 9877 (specified by WRS). It is an intimation
that the server is ready to accept a connection destined for any local interface in case the
system is multi homed.

Line 14 : bind () function binds the address specified by the address structure to the
socket.
Line 15: The socket is converted into listening socket by the call to the listen()function
Line 17-18: The server blocks in the call to accept, waiting for a client connection to
complete.
Line 19 – 24: For each client, fork() spawns a child and the child handles the new client.
The child closes the listening socket and the parent closes the connected socket The child
then calls str_echo () to handle the client

Dept of CSE 24
Module-2 Network Programming

Module-3
I/O Multiplexing and Socket Options-I/O Modules, select function, str_cli function, batch
input and buffering shutdown function, TCP Echo Server, pselect function, poll function.

I/O Multiplexing and Socket Options


It is seen that the TCP client is handling two inputs at the same time: standard
input and a TCP socket. It was found that when the client was blocked in a call to read(by
calling readline function), and the server process was killed. The server TCP correctly,
correctly sends a FIN to the client TCP, but since the client process is blocked reading
from the standard input, it never sees the end – of file until it reads from the socket . What
we need is the capability to tell the kernel that we want to be notified if one or more I/O
conditions are ready (i.e. input is ready to be read, or the descriptors is capable of taking
more outputs). This capability is called I /O Multiplexing and is provided by
the select and poll functions . There is one more Posix .1g variations called pselect.

I /O multiplexing is typically is used in networking applications in the following


scenarios:

• When a client is handling multiple descriptors ( normally interactive input and


a network socket), I/O multiplexing should be used. This is the scenario that was
described in the previous paragraph.
• It is possible, but rare, ofr a client to handle multiple sockets at the same
time. We show an example of this using select in the context of web client

• If a TCP server handles both a listening socket and its connected sockets, I / O
multiplexing is normally used.

• IF a server handles both TCP and UDP, I/O multiplexing is normally used.

• If a server handles multiple services and perhaps multiple protocols, I/O


multiplexing us normally used.

Dept of CSE 25
Module-2 Network Programming

It is not restricted only to networking programme, it may be used in any nontrivial


application as well.

I/O Models:
There are five I /O models in the Unix. These are:
a. Blocking I /O
b. Non blocking I / O
c. I/O Multiplexing (select and poll)
d. Signal driven I/O (SIGIO)
e. Asynchronous I/O (the Posix 1 aio_functions)

There are two distinct phases for an input operation.:


a. waiting for the data to be read and
b. copying the data from the kernel to the process.

Fo ran input operation on a socket the first step normally involves waiting for the
data to arrive on the network. When the packet arrives, it is copied into buffer within
the kernel. The second step is copying this data from the kernel‘s buffer into our
applications buffer.

Blocking I/O Model :

The most prevalent model for I/O is the blocking I/O model, which we have used for all
our examples so far in the text.. BY default, all sockets are blocking. Using a datagram
socket for our examples we have the scenario as shown below. In UDP the concept of data
being ready to be read is simple because either an entire datagram packet is received or
not.

IN this example recvfrom as a system call as it differentiated between our application and
the kernel.

Dept of CSE 26
Module-2 Network Programming

The process calls recvfrom and the system call does not return until the datagram arrives
and is copied into our application buffer, or an error occurs. The most common error is the
system call being interrupted by a signal. We say that our process is blocked the entire time
from when it call recvfrom until it returns. When recvfrom returns OK, our application
processes the datagram.

Non Blocking I/O Model :


When the socket is set to non blocking, the kernel is told that ―when I/O operation that I
request cannot be completed without putting the process to sleep, do not put the process to
sleep but return an error message instead.‖ The following figure gives the details.

Dept of CSE 27
Module-2 Network Programming

During the first three times, when the recvfrom is called, there is no data to return, so the
kernel immediately returns an error EWOULDBLOCK. Fourth time, when recvfrom is
called, the datagram is ready, it is copied into our application buffer and
the recvfrom returns OK. The application then process the data.

When the application puts the call recvfrom in a loop, on a non blocking descriptors like
this, it is called polling. The continuation polling of the kernel is waste of CPU time. But
this model is normally encountered on system that are dedicated to one function.
Signal Driven I/O Model
Signals are used to tell the kernel to notify applications with the SIGIO signal when
the descriptor is ready. It is called signal driven I/O Model. The summary is shown in
the following figure.
First enable the socket for the signal driven I/O and install a signal handler using
the sigaction system call. The return from this system call is immediate and our process
continuous, it is not block. When the datagram is ready to be ready, the SIGIO signal is
generated for our process. We can either read the datagram from the signal handler by

Dept of CSE 28
Module-2 Network Programming

calling recvfrom and then notify the main loop that the data is ready to be process, or we
can notify the main lop and let it read the datagram.
The advantage I this model is that we are not blocked while waiting for the datagram top
arrive. The main loop can continue executing and just wait to be notified by the signal
handler that either the dta is read to process or that the datagram is ready to be read.

Asynchronous I/O Model

Asynchronous I/O are new with the 1993 edition of Posix 1g. In this the kernel is
told to start operation and to notify when the entire operation (including the copy of the
data from the kernel to our buffer ) is over.

The main difference between this and the signal driven I/O model in the previous
section is that with the signal driven I/O the kernel tells when the I/O operation
can be initiated. But with asynchronous I/O, the kernel tells us when an I/O
operation is complete. It is summarized as given below:

Dept of CSE 29
Module-2 Network Programming

The function aio_read is called and the descriptor, buffer pointer, buffer size, file
offset and how to notify when the entire operation is complete are passed to the kernel.
The system calls returns immediately and our process is not blocked waiting for the I./O
to complete. It is expected that the kernel will generate some signal when the operation is
complete. The signal is generated only when the data is copied completely in the
application buffer.
Comparison of the I/O Model

Dept of CSE 30
Module-2 Network Programming

The main difference between the four models is the first phase as the second phase
in the first four models is the same. The process is blocked in a cal to recvfrom while the
data is copied from the kernel to the caller‘s buffer. Asynchronous I/O however, handles
both the phases and is different form the first four.

Synchronous vs asynchronous:
A synchronous I/O operation causes the requesting process to be blocked until that
I?O operation is completes.
An asynchronous I/O operation does not cause the requesting process to be blocked.

Dept of CSE 31
Module-2 Network Programming

Based on this definition, the first four are synchronous as the actual I/O operation
blocks the process. Only asynchronous I/O model matches the asynchronous I/O
definition.
Select Function :
The select function allows the process to instruct the kernel to wait for any one of
the multiple events to occur and to wake up the process only when one or more of these
events occurs or when a specified amount of time has passed.
As an example, we can call select and tell the kernel to return only
• any of the descriptors in the set { 1,4,5} are ready for reading, or
• any of the descriptors in the set {2,7} are ready for writing, or
• any of the descriptors in the set {1,4 } have an exception condition pending or
• after 10.2. seconds have elapsed.
That the kernel is told in what descriptors we are interested in (for reading, writing or
an exception condition) and how long to wait. The descriptors in which we are
interested are not restricted to sockets: any descriptor can be tested using select.

#include <sys/select.h> #include <sys/time.h>

int select (int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *excepset, const
struct timeval *timeout); returns : positive count of ready descriptors, o on timeout, -1 on
error.
Consider the final arguments: This tells the kernel how long to wait for one of the
specified descriptors to become ready. A timeval structure specifies the number of
seconds and microseconds.

Struct timeval
long tv_sec; /* seconds */
long tv_usec; /* micros seconds */
}
There are three possibilities:
• wait forever: return only when one of the specified descriptors is ready for I/O
. For this, we specify the timeout argument as a null pointer.

Dept of CSE 32
Module-2 Network Programming

• Wait upto a fixed amount of time: return when one of the specified descriptors
is ready for I/O, but do not wait beyond the number of seconds and microseconds
specified in the timeval structure pointer to by the timeout argument.

• Do not wait at all: return immediately after checking the descriptors. This is
called polling. To specify this, the timeout argument must point to a timeval
structure and the timer value must be zero
In case of first two scenario, the wait is normally interrupted if the process catches a
signal and returns from the signal handler.
The const qualifier on the timeout argument means it is not modified by select on
return. For example, if we specify a time limit of 10 sec, and select returns before the
timer expires, with one or more descriptors ready or with an error of EINTR, the
timeval structure is not updated with the number of seconds remaining when the
functions returns.
The three middle arguments readset, writeset and excepset specify the descriptors
that we want the kernel to test for reading, writing and exception conditions.
The two exceptions conditions currently supported are:
• The arrival of out of bound data for a socket.

• The control status information to be read from the master side of pseudo
terminal

The maxfdp1 argument specifies the number of descriptors to be tested. Its value is the
maximum descriptors to be tested plus one. The descriptors 0,1,2, through and
including maxfdp1 –1 are tested. The constant FD_SETSIZE defined by including <sys
/select.h>, is the number of descriptors in the fd_set

data type. It s value is often 1024, but few programs use that many descriptors.
The maxfdp1 argument forces us to calculate the largest descriptors that we are interested
in and then tell the kernel this value. For 1,4,5 the maxfdp1 is 6.
The design problem is how to specify one or more descriptors values for each of these three
arguments. Select uses descriptor sets, typically an array of integers – a32 by 32 array- of
1024 descriptors set. The descriptors are programmed for initializing /reading / writing and
for closing using the following macros:

Dept of CSE 33
Module-2 Network Programming

void FD_ZERO (fd_set * fset) /* clear all bits in fset */


void FD_SET (int fd, fd_set * fset) /* Turn on the bit for fd in fset*/
void FD_CLR (int fd, fd_set * fset) /*turn off the bit for fd in fset
void FD_ISSET (int fd, fd_set * fset) /* is the bit for fd on in fset? */
For example to define a variable of type fd_set and then turn on the bits for descriptors, we
write
fd_set rset;
FD_ZERO (&rset); /* initialize the set; all bits to zet */
FD_SET (1, &rset); /* turn on bit for fd 1
FD_SET (4, &rset ); /* turn on bit for fd 4; */
If the descriptors are initialized to zero, unexpected results are likely to come.
Middle arguments to select, readset, writeset, or exceptset can be specified as null pointer,
if we are not interest in that condition. The maxfdp1 arguments specifies the number of
descriptors to be tested. Its value is the maximum descriptors to be tested, plus one (hence
the name maxfdp1). The descriptors 0,1,2 up through and including maxfdp1 – 1 are tested.

Select function modifies the descriptor sets pointed by the readset, writset and excepset
pointers. These three arguments are value-result arguments. When we call the function, we
specify the values of the descriptors that we are interested in and on return the result
indicates which descriptors are ready. We use FD_ISSET macros return to test a specific
descriptor in an fd_set structure. Any descriptors that is not ready on return will have its
corresponding bit cleared in the descriptors set.

str_cli Function :
The str_cli Function is rewritten using the select function as shown below:
# include ―unp.h‖

void str_cli (FILE *fp, int socket)


{
int maxfdp1;

Dept of CSE 34
Module-2 Network Programming

fd_set rset;
char sendline[MAXLINE], recvline[MAXLINE];
FD_ZERO (&rset);
for ( ; ;)
{
FD_SET (fileno (fp), &rset);
FD_SET (sockfd, &rset);
maxfdp1 = max (fileno (fp), sockfd) + 1;
select (maxfdp1, &rset, NULL, NULL, NULL);

if (FD_ISSET(sockfd, &rset))
{ if (readline (sockfd, recvline, MAXLINE)==0)

err_quit (―str_cli: server terminated prematurely‖); fputs (recvline, stdout);


}

if (FD_ISSET(fileno(fp), &rset))

{if (fgets (sendline, MAXLINE, fp)==NULL) return;

writen(sockfd, sendline, strlen (sendline));

}
}

Dept of CSE 35
Module-2 Network Programming

IN the above code the descriptors set is initialized to zero using FD_ZERO. Then, the
descriptors, file pointer fp and socket sockfd are turned on using FD_SET. maxfdp1 is
calculated from the descriptors list. Select function is called. IN this writeset pointer and
exception set pointers are both NULL. Final time pointer is also NULL as the call is to be
blocked until something is ready.
If on return from the select, socket is readable, the echoed line is read
with readline and output by fputs.
If the standard input is readable, a line is read by fget sand written to the sockets
using writen.
IN this although the four functions fgets, writen, readline and fputs are used, the order of
flow within the function has changed. In this, instead of flow being driven by the call to
fgets, it is driven by the call to select.
This has enhanced the robustness of the client.
Batch Input:
The echo client server, works in a stop and wait mode. That is , it sends a line to the server
and then waits for the reply. This amount of time is one RTT (Round Trip Time) plus the
server‘s processing time. If we consider the network between the client and the server as a
full duplex pipe with requests from the client to server, and replies in the reverse direction,
then the following shows the stop and wait mode.

Dept of CSE 36
Module-2 Network Programming

The request is sent by the client at time 0 and we assume RTT of 8 units of time.
The reply sent at a time 4 is received at time 7. It is assumed that there is no serving
processing time and that the size of the request is the same as the reply. Also, TCP
acknowledgment are ignored.
But as there is a delay between sending a packet and that packet arriving at the
other end of the pipe, and since the pipe is full duplex, in this example we are only
using one- eighth of the pipe capacity.
This stop and wait mode is fine for interactive input, but since our client reads from
standard input and writes to standard output, we can easily run our client in a batch mode.
When the input is redirected as in client server example, the output file is always same.
To see what is happening in the batch mode, we can keep sending requests as fast as the
network can accept them. The server processes them and sends back the replies at the same
rate. This leads to the full pipe at time 7 as shown below:

Dept of CSE 37
Module-2 Network Programming

Filling the pipe between the client and the sever : batch Mode;

Now to understand the problem with the str_cli, let the input file contains only nine
lines. The last line is sent at time 8 as shown above. But we cannot close the connection
after writing this request, because there are still other requests and rep0les in the pipe. The
cause of the problem is our handling of end of file on input. The function returns to the
main function, which then terminates. But in a batch mode, an end of file on the input
does not imply. That we have finished reading from the socket. There might still requests
on the way to the server or replies on the way to back from the server.

Dept of CSE 38

You might also like