You are on page 1of 31

MODULE 40

NETWORK PROGRAMMING
SOCKET PART II

My Training Period: hours

Note:
This is a continuation from Part I, Module 39. Working program examples compiled using gcc, tested using the
public IPs, run on Fedora 3, with several times of update, as normal user. The Fedora machine used for the testing
having the "No Stack Execute" disabled and the SELinux set to default configuration.

Abilities

Able to understand and use the Unix/Linux C language socket APIs.
Able to und stand and implement several simple TCP and UDP Client and server basic designs. er
Client Design Consideration


- Some of the information in this section is a repetition from the previous one.

Identifying a Server's Address

- A server's ip address must be used in connect.
- Usually the name is used to get the address.
- The name could be in the code mai l host for an email program.
- The user could specify the name common because it is flexible and simple.
- The name or address could be in a file.
- Broadcast on the network to ask for a server.
- Example telneting the t el ser v. t est . comserver through the standard telnet port 25:

t el net t el ser v. t est . com

- Or using the IP address of the telnet server:

t el net 131. 95. 115. 204

- Client software typically allows either names or numbers.
- Ports usually have a default value in the code if not explicitly mentioned.

Looking Up a Computer Name

NAME
get host byname( ) - get net wor k host ent r y

SYNOPSI S
#i ncl ude <net db. h>
ext er n i nt h_er r no;

st r uct host ent
*get host byname( const char *name) ;
st r uct host ent {
char *h_name;
char **h_al i ases;
i nt h_addr t ype;
i nt h_l engt h;
char **h_addr _l i st ;
};
#def i ne h_addr h_addr _l i st [ 0]

- name could be a name or dotted decimal address.
- Hosts can have many names in h_al i ases.
- Hosts can have many addresses in h_addr _l i st .
- Addresses in h_addr _l i st are not strings network order addresses ready to copy and use.

Looking Up a Port Number by Name

www.tenouk.com
NAME
get ser vbyname( ) - get ser vi ce ent r y

SYNOPSI S
#i ncl ude <net db. h>

st r uct ser vent *get ser vbyname( const char *name, const char *pr ot o) ;

st r uct ser vent {
char *s_name;
char **s_al i ases;
i nt s_por t ;
char *s_pr ot o;
}

- s_por t : port number for the service given in network byte order.

Looking Up a Protocol by Name

NAME
get pr ot obyname( ) - get pr ot ocol ent r y

SYNOPSI S
#i ncl ude <net db. h>

st r uct pr ot oent
*get pr ot obyname( const char *name) ;
st r uct pr ot oent {
char *p_name;
char **p_al i ases;
i nt p_pr ot o;
}

- p_pr ot o: the protocol number (can be used in socket call).

getpeername()

- The function getpeername() will tell you who is at the other end of a connected stream socket.
- The prototype:

#i ncl ude <sys/ socket . h>
i nt get peer name( i nt sockf d, st r uct sockaddr *addr , i nt *addr l en) ;

- sockfd is the descriptor of the connected stream socket.
- addr is a pointer to a struct sockaddr (or a struct sockaddr_in) that will hold the
information about the other side of the connection.
- addrlen is a pointer to an int, which should be initialized to si zeof ( st r uct sockaddr ) .
- The function returns -1 on error and sets errno accordingly.
- Once you have their address, you can use inet_ntoa() or gethostbyaddr() to print or get
more information.

Allocating a Socket

#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>

i nt s;

s = socket ( PF_I NET, SOCK_STREAM, 0) ;

- Specifying PF_I NET and SOCK_STREAMleaves the protocol parameter irrelevant.

Choosing a Local Port Number

- The server will be using a well-known port.
- Once a client port is set, the server will be aware as needed.
- You could bind to a random port above 1023.
- A simpler choice is to leave out the bind call.
- connect ( ) will choose a local port if required.
www.tenouk.com

Connecting to a Server with TCP

- connect ( ) .

NAME
connect - i ni t i at e a connect i on on a socket

SYNOPSI S
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>

i nt connect ( i nt s, st r uct sockaddr *ser v_addr , i nt addr l en) ;

RETURN VALUE
I f t he connect i on or bi ndi ng succeeds, zer o i s r et ur ned.
On er r or , - 1 i s r et ur ned, and er r no i s set appr opr i at el y.

- We will use a sockaddr _i n structure (possibly cast).
- After connect, s is available to read/write.

Communicating with TCP

- Code segment example:

char *r eq = " send cash" ;
char buf [ 100] , *b;

wr i t e ( s, r eq, st r l en( r eq) ) ;

l ef t = 100;
b = buf ;
whi l e ( l ef t && ( n = r ead( s, buf , l ef t ) ) > 0)
{
b += n;
l ef t - = n;
}

- The client and server can not know how many bytes are sent in each write.
- Delivered chunks are not always the same size as in the original write.
- Reads must be handled in a loop to cope with stream sockets.

Closing a TCP Connection

- In the simplest case close works well.
- Sometimes it is important to tell the server that a client will send no more requests, while still keeping
the socket available for reading.

r es = shut down( s, 1) ;

- The 1 means no more writes will happen.
- The server detects end of file on the socket.
- After the server sends all the replies it can close.

Connected vs Unconnected UDP Sockets

- A client can call connect with a UDP socket or not.
- If connect is called read and write will work.
- Without connect the client needs to send with a system call specifying a remote endpoint.
- Without connect it might be useful to receive data with a system call which tells the remote endpoint.
- Connect with TCP involves a special message exchange sequence.
- Connect with UDP sends no messages. You can connect to non-existent servers.

Communicating with UDP

- UDP data is always a complete message (datagram).
- Whatever is specified in a write becomes a datagram.
www.tenouk.com
- Receiver receives the complete datagram unless fewer bytes are read.
- Reading in a loop for a single datagram is pointless with UDP.
- cl ose( ) is adequate, since shut down( ) does not send any messages.
- UDP is unreliable. UDP software needs an error protocol.

Example Clients Some variations

A Simple Client Library

- To make a connection, a client must:

sel ect UDP or TCP. . .
det er mi ne a ser ver ' s I P addr ess. . .
det er mi ne t he pr oper por t . . .
make t he socket cal l . . .
make t he connect cal l . . .

- Frequently the calls are essentially the same.
- A library offers normal capability with a simple interface.

connectTCP()

- The following is a code segment example using the connect TCP( ) function.

i nt connect TCP( const char *host , const char *ser vi ce)
{ r et ur n connect sock( host , ser vi ce, " t cp" ) ; }

connectUDP()

- The following is a code segment example using the connect UDP( ) function.

i nt connect UDP( const char *host , const char *ser vi ce)
{ r et ur n connect sock( host , ser vi ce, " udp" ) ; }

connectsock()

- The following is a code segment example using the connect sock( ) function.

i nt connect sock( const char *host , const char *ser vi ce, const char *t r anspor t )
{
st r uct host ent *phe; / * poi nt er t o host i nf or mat i on ent r y */
st r uct ser vent *pse; / * poi nt er t o ser vi ce i nf or mat i on ent r y */
st r uct pr ot oent *ppe; / * poi nt er t o pr ot ocol i nf or mat i on ent r y*/
st r uct sockaddr _i n si n; / * an I nt er net endpoi nt addr ess */
i nt s, t ype; / * socket descr i pt or and socket t ype */

memset ( &si n, 0, si zeof ( si n) ) ;
si n. si n_f ami l y = AF_I NET;

/ * Map ser vi ce name t o por t number */
i f ( pse = get ser vbyname( ser vi ce, t r anspor t ) )
si n. si n_por t = pse- >s_por t ;
el se i f ( ( si n. si n_por t = ht ons( ( u_ shor t ) at oi ( ser vi ce) ) ) == 0)
er r exi t ( " can' t get \ " %s\ " ser vi ce ent r y\ n" , ser vi ce) ;

/ * Map host name t o I P addr ess, al l owi ng f or dot t ed deci mal */
i f ( phe = get host byname( host ) )
memcpy( &si n. si n_addr , phe- >h_addr , phe- >h_l engt h) ;
el se i f ( ( si n. si n_addr . s_addr = i net _addr ( host ) ) == I NADDR_NONE)
er r exi t ( " can' t get \ " %s\ " host ent r y\ n" , host ) ;

/ * Map t r anspor t pr ot ocol name t o pr ot ocol number */
i f ( ( ppe = get pr ot obyname( t r anspor t ) ) == 0)
er r exi t ( " can' t get \ " %s\ " pr ot ocol ent r y\ n" , t r anspor t ) ;

/ * Use pr ot ocol t o choose a socket t ype */
i f ( st r cmp( t r anspor t , " udp" ) == 0)
t ype = SOCK_DGRAM;
el se
www.tenouk.com
t ype = SOCK_STREAM;

/ * Al l ocat e a socket */
s = socket ( PF_I NET, t ype, ppe- >p_pr ot o) ;
i f ( s < 0)
er r exi t ( " can' t cr eat e socket : %s\ n" , st r er r or ( er r no) ) ;

/ * Connect t he socket */
i f ( connect ( s, ( st r uct sockaddr *) &si n, si zeof ( si n) ) < 0)
er r exi t ( " can' t connect t o %s. %s: %s\ n" , host , ser vi ce, st r er r or ( er r no) ) ;
r et ur n s;
}

A TCP DAYTIME Client

- DAYTI ME service prints date and time.
- TCP version sends upon connection. Server reads no client data.
- UDP version sends upon receiving any message.
- The following is a code segment example implementing the TCP Daytime.

#def i ne LI NELEN 128

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
/ * host t o use i f none suppl i ed */
char *host = " l ocal host " ;
/ * def aul t ser vi ce por t */
char *ser vi ce = " dayt i me" ;
swi t ch ( ar gc) {
case 1:
host = " l ocal host " ;
br eak;
case 3:
ser vi ce = ar gv[ 2] ;
/ * FALL THROUGH */
case 2:
host = ar gv[ 1] ;
br eak;
def aul t :
f pr i nt f ( st der r , " usage: TCPdayt i me [ host [ por t ] ] \ n" ) ;
exi t ( 1) ;
}
TCPdayt i me( host , ser vi ce) ;
exi t ( 0) ;
}

voi d TCPdayt i me( const char *host , const char *ser vi ce)
{
/ * buf f er f or one l i ne of t ext */
char buf [ LI NELEN+1] ;
/ * socket , r ead count */
i nt s, n;

s = connect TCP( host , ser vi ce) ;

whi l e( ( n = r ead( s, buf , LI NELEN) ) > 0)
{
/ * ensur e nul l - t er mi nat ed */
buf [ n] = ' \ 0' ;
( voi d) f put s( buf , st dout ) ;
}
}

A UDP TIME Client

- The TI ME service is for computers.
- Returns seconds since 1-1-1900.
- Useful for synchronizing and time-setting.
- TCP and UDP versions return time as an integer.
- Need to use nt ohl to convert.
- The following is a code segment example implementing UDP Time.

#def i ne MSG " What t i me i s i t ?\ n"
www.tenouk.com

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
char *host = " l ocal host " ; / * host t o use i f none suppl i ed */
char *ser vi ce = " t i me" ; / * def aul t ser vi ce name */
t i me_t now; / * 32- bi t i nt eger t o hol d t i me */
i nt s, n; / * socket descr i pt or , r ead count */

swi t ch ( ar gc) {
case 1:
host = " l ocal host " ;
br eak;
case 3:
ser vi ce = ar gv[ 2] ;
/ * FALL THROUGH */
case 2:
host = ar gv[ 1] ;
br eak;
def aul t :
f pr i nt f ( st der r , " usage: UDPt i me [ host [ por t ] ] \ n" ) ;
exi t ( 1) ;
}

s = connect UDP( host , ser vi ce) ;

( voi d) wr i t e( s, MSG, st r l en( MSG) ) ;

/ * Read t he t i me */
n = r ead( s, ( char *) &now, si zeof ( now) ) ;
i f ( n < 0)
er r exi t ( " r ead f ai l ed: %s\ n" , st r er r or ( er r no) ) ;
/ * put i n host byt e or der */
now = nt ohl ( ( u_l ong) now) ;
pr i nt f ( " %s" , ct i me( &now) ) ;
exi t ( 0) ;
}

TCP and UDP Echo Clients

- mai n( ) is like the other clients.

TCPecho() function

- The following is a code segment example for using the TCPecho( ) function.

i nt TCPecho( const char *host , const char *ser vi ce)
{
char buf [ LI NELEN+1] ; / * buf f er f or one l i ne of t ext */
i nt s, n; / * socket descr i pt or , r ead count */
i nt out char s, i nchar s; / * char act er s sent and r ecei ved */

s = connect TCP( host , ser vi ce) ;

whi l e( f get s( buf , si zeof ( buf ) , st di n) )
{
/ * i nsur e l i ne nul l - t er mi nat ed */
buf [ LI NELEN] = ' \ 0' ;
out char s = st r l en( buf ) ;
( voi d) wr i t e( s, buf , out char s) ;

/ * r ead i t back */
f or ( i nchar s = 0; i nchar s < out char s; i nchar s+=n)
{
n = r ead( s, &buf [ i nchar s] , out char s - i nchar s) ;
i f ( n < 0)
er r exi t ( " socket r ead f ai l ed: %s\ n" , st r er r or ( er r no) ) ;
}
f put s( buf , st dout ) ;
}
}

UDPecho() function

- The following is a code segment example for using the UDPecho( ) function.
www.tenouk.com

i nt UDPecho( const char *host , const char *ser vi ce)
{
/ * buf f er f or one l i ne of t ext */
char buf [ LI NELEN+1] ;
/ * socket descr i pt or , r ead count */
i nt s, nchar s;

s = connect UDP( host , ser vi ce) ;

whi l e( f get s( buf , si zeof ( buf ) , st di n) )
{
/ * ensur e nul l - t er mi nat ed */
buf [ LI NELEN] = ' \ 0' ;
nchar s = st r l en( buf ) ;
( voi d) wr i t e( s, buf , nchar s) ;

i f ( r ead( s, buf , nchar s) < 0)
er r exi t ( " socket r ead f ai l ed: %s\ n" , st r er r or ( er r no) ) ;
f put s( buf , st dout ) ;
}
}

Server Design Consideration

Concurrent vs Iterati ve Servers

- An iterative server processes one request at a time.
- A concurrent server processes multiple requests at a time real or apparent concurrency.
- A single process can use asynchronous I/O to achieve concurrency.
- Multiple server processes can achieve concurrency.
- Concurrent servers are more complex.
- Iterative servers cause too much blocking for most applications.
- Avoiding blocking results in better performance.

Connection-Oriented vs Connectionless Servers

- TCP provides a connection-oriented service.
- UDP provides a connectionless service.

Connection-oriented Servers

- Easy to program, since TCP takes care of communication problems.
- Also a single socket is used for a single client exclusively (connection).
- Handling multiple sockets is intense juggling.
- For trivial applications the 3-way handshake is slow compared to UDP.
- Resources can be tied up if a client crashes.

Connectionless Servers

- No resource depletion problem.
- Server/client must cope with communication errors. Usually client sends a request and resends if
needed.
- Selecting proper timeout values is difficult.
- UDP allows broadcast/multicast.

Stateless Servers

- Statelessness improves reliability at the cost of longer requests and slower performance.
- Improving performance generally adds state information. For example, adding a cache of file data.
- Crashing clients leave state information in server.
- You could use LRU replacement to re-use space.
- A frequently crashing client could dominate the state table, wiping out performance gains.
- Maintaining state information correctly and efficiently is complex.

Request Processing Time

www.tenouk.com
- Request processing time (rpt) =total time server uses to handle a single request.
- Observed response time (ort) =delay between issuing a request and receiving a response
- rpt <=ort.
- If the server has a large request queue, ort can be large.
- Iterative servers handle queued requests sequentially.
- With N items queued the average iterative (ort =N * rpt).
- With N items queued a concurrent server can do better.
- Implementations restrict queue size.
- Programmers need a concurrent design if a small queue is inadequate.

Iterati ve, Connection-Oriented Server Algorithm

- The following is a sample of pseudo codes for iterative, connection oriented server.

cr eat e a socket
bi nd t o a wel l - known por t
pl ace i n passi ve mode
whi l e ( 1)
{
Accept t he next connect i on
whi l e ( cl i ent wr i t es)
{
r ead a cl i ent r equest
per f or mr equest ed act i on
send a r epl y
}
cl ose t he cl i ent socket
}
cl ose t he passi ve socket

Using INADDR_ANY

- Some server computers have multiple IP addresses.
- A socket bound to one of these will not accept connections to another address.
- Frequently you prefer to allow any one of the computer's IP addresses to be used for connections.
- Use I NADDR_ANY (0L) to allow clients to connect using any one of the host's IP addresses.

Iterati ve, Connectionless Server Algorithm

- The following is a sample of pseudo codes for iterative, connectionless server.

cr eat e a socket
bi nd t o a wel l - known por t
whi l e ( 1)
{
r ead a r equest f r omsome cl i ent
send a r epl y t o t hat cl i ent
}

r ecvf r om( s, buf , l en, f l ags, f r om, f r oml en)
sendt o( s, buf , l en, f l ags, t o, t o_l en)

Concurrent, Connectionless Server Algorithm

- The following is a sample of pseudo codes for concurrent, connectionless server.

cr eat e a socket
bi nd t o a wel l - known por t
whi l e ( 1)
{
r ead a r equest f r omsome cl i ent
f or k
i f ( chi l d)
{
send a r epl y t o t hat cl i ent
exi t
}
}

- Overhead of fork and exit is expensive.
- Not used much.
www.tenouk.com

Concurrent, Connection-Oriented Server Algorithm

- The following is a sample of pseudo codes for connection-oriented server.

cr eat e a socket
bi nd t o a wel l - known por t
use l i st en t o pl ace i n passi ve mode
whi l e ( 1)
{
accept a cl i ent connect i on
f or k
i f ( chi l d)
{
communi cat e wi t h new socket
cl ose new socket
exi t
}
el se
{cl ose new socket }
}

- Single program has master and slave code.
- It is possible for slave to use execve.

Concurrency Using a Single Process

- The following is a sample of pseudo codes for concurrency using a single process.

cr eat e a socket
bi nd t o a wel l - known por t
whi l e ( 1)
{
use sel ect t o wai t f or I / O
i f ( or i gi nal socket i s r eady)
{
accept ( ) a new connect i on and add t o r ead l i st
}
el se i f ( a socket i s r eady f or r ead)
{
r ead dat a f r oma cl i ent
i f ( dat a compl et es a r equest )
{
do t he r equest
i f ( r epl y needed) add socket t o wr i t e l i st
}
}
el se i f ( a socket i s r eady f or wr i t e)
{
wr i t e dat a t o a cl i ent
i f ( message i s compl et e)
{
r emove socket f r omwr i t e l i st
}
el se
{
adj ust wr i t e par amet er s and l eave i n wr i t e l i st
}
}
}

When to Use the Various Server Types

- Iterative vs Concurrent.

Iterative server is simpler to write.
Concurrent server is faster.
Use iterative if it is fast enough.

- Real vs Apparent Concurrency.

Writing a single process concurrent server is harder.
Use a single process if data must be shared between clients.
www.tenouk.com
Use multiple processes if each slave is isolated or if you have multiple CPUs.

- Connection-Oriented vs Connectionless.

Use connectionless if the protocol handles reliability.
Use connectionless on a LAN with no errors.

Avoiding Server Deadlock

- Client connects but sends no request. Server blocks in read call.
- Client sends request, but reads no replies. Server blocks in write call.
- Concurrent servers with slaves are robust.

Iterati ve, Connectionless Servers (UDP)

Creating a Passi ve UDP Socket

- The following is a sample codes for a passive UDP socket.

i nt passi veUDP( const char *ser vi ce)
{
r et ur n passi vesock( ser vi ce, " udp" , 0) ;
}

u_shor t por t base = 0;

i nt passi vesock( const char *ser vi ce, const char *t r anspor t , i nt ql en)
{
st r uct ser vent *pse;
st r uct pr ot oent *ppe;
st r uct sockaddr _i n si n;
i nt s, t ype;

memset ( &si n, 0, si zeof ( si n) ) ;
si n. si n_f ami l y = AF_I NET;
si n. si n_addr . s_addr = I NADDR_ANY;

/ * Map ser vi ce name t o por t number */
i f ( pse = get ser vbyname( ser vi ce, t r anspor t ) )
si n. si n_por t = ht ons( nt ohs( ( u_shor t ) pse- >s_por t ) + por t base) ;
el se i f ( ( si n. si n_por t = ht ons( ( u_shor t ) at oi ( ser vi ce) ) ) == 0)
er r exi t ( " can' t get \ " %s\ " ser vi ce ent r y\ n" , ser vi ce) ;

/ * Map pr ot ocol name t o pr ot ocol number */
i f ( ( ppe = get pr ot obyname( t r anspor t ) ) == 0)
er r exi t ( " can' t get \ " %s\ " pr ot ocol ent r y\ n" , t r anspor t ) ;

/ * Use pr ot ocol t o choose a socket t ype */
i f ( st r cmp( t r anspor t , " udp" ) == 0)
t ype = SOCK_DGRAM;
el se
t ype = SOCK_STREAM;

/ * Al l ocat e a socket */
s = socket ( PF_I NET, t ype, ppe- >p_pr ot o) ;
i f ( s < 0)
er r exi t ( " can' t cr eat e socket : %s\ n" , st r er r or ( er r no) ) ;

/ * Bi nd t he socket */
i f ( bi nd( s, ( st r uct sockaddr *) &si n, si zeof ( si n) ) < 0)
er r exi t ( " can' t bi nd t o %s por t : %s\ n" , ser vi ce, st r er r or ( er r no) ) ;
i f ( t ype == SOCK_STREAM && l i st en( s, ql en) < 0)
er r exi t ( " can' t l i st en on %s por t : %s\ n" , ser vi ce, st r er r or ( er r no) ) ;
r et ur n s;
}

A TIME Server

- The following is a sample codes for Time server.

/ * mai n( ) - I t er at i ve UDP ser ver f or TI ME ser vi ce */
i nt mai n( i nt ar gc, char *ar gv[ ] )
www.tenouk.com
{
st r uct sockaddr _i n f si n ;
char *ser vi ce = " t i me" ;
char buf [ 1] ;
i nt sock;
t i me_t now;
i nt al en;

sock = passi veUDP( ser vi ce) ;

whi l e ( 1)
{
al en = si zeof ( f si n) ;
i f ( r ecvf r om( sock, buf , si zeof ( buf ) , 0, ( st r uct sockaddr *) &f si n, &al en) < 0)
er r exi t ( " r ecvf r om: %s\ n" , st r er r or ( er r no) ) ;
t i me( &now) ;
now = ht onl ( ( u_l ong) now) ;
sendt o( sock, ( char *) &now, si zeof ( now) , 0, ( st r uct sockaddr *) &f si n, si zeof ( f si n) ) ;
}
}

Iterati ve, Connection-Oriented Servers (TCP)

A DAYTIME Server

- The following is a sample codes for Daytime server.

i nt passi veTCP( const char *ser vi ce, i nt ql en)
{
r et ur n passi vesock( ser vi ce, " t cp" , ql en) ;
}

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
st r uct sockaddr _i n f si n;
char *ser vi ce = " dayt i me" ;
i nt msock, ssock;
i nt al en;

msock = passi veTCP( ser vi ce, 5) ;

whi l e ( 1) {
ssock = accept ( msock, ( st r uct sockaddr *) &f si n, &al en) ;
i f ( ssock < 0)
er r exi t ( " accept f ai l ed: %s\ n" , st r er r or ( er r no) ) ;
TCPdayt i med( ssock) ;
cl ose( ssock) ;
}
}

voi d TCPdayt i med( i nt f d)
{
char *pt s;
t i me_t now;
char *ct i me( ) ;

t i me( &now) ;
pt s = ct i me( &now) ;
wr i t e( f d, pt s, st r l en( pt s) ) ;
r et ur n;
}

- Close call requests a graceful shutdown.
- Data in transit is reliably delivered.
- Close requires messages and time.
- If the server closes you may be safe.
- If the client must close, the client may not cooperate.
- In our simple server, a client can make rapid calls and use resources associated with TCP shutdown
timeout.

Concurrent, Connection-Oriented Servers (TCP)

The Value of Concurrency
www.tenouk.com

- An iterative server may block for excessive time periods.
- An example is an echo server. A client could send many megabytes blocking other clients for
substantial periods.
- A concurrent echo server could handle multiple clients simultaneously. Abusive clients would not
affect polite clients as much.

A Concurrent Echo Server Using fork()

- The following is a sample codes for concurrent Echo server using f or k( ) .

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
char *ser vi ce = " echo" ; / * ser vi ce name or por t number */
st r uct sockaddr _i n f si n; / * t he addr ess of a cl i ent */
i nt al en; / * l engt h of cl i ent ' s addr ess */
i nt msock; / * mast er ser ver socket */
i nt ssock; / * sl ave ser ver socket */

msock = passi veTCP( ser vi ce, QLEN) ;

si gnal ( SI GCHLD, r eaper ) ;

whi l e ( 1)
{
al en = si zeof ( f si n) ;
ssock = accept ( msock, ( st r uct sockaddr *) &f si n, &al en) ;
i f ( ssock < 0) {
i f ( er r no == EI NTR)
cont i nue;
er r exi t ( " accept : %s\ n" , st r er r or ( er r no) ) ;
}
swi t ch ( f or k( ) )
{
/ * chi l d */
case 0:
cl ose( msock) ;
exi t ( TCPechod( ssock) ) ;
/ * par ent */
def aul t :
cl ose( ssock) ;
br eak;
case - 1:
er r exi t ( " f or k: %s\ n" , st r er r or ( er r no) ) ;
}
}
}

i nt TCPechod( i nt f d)
{
char buf [ BUFSI Z] ;
i nt cc;

whi l e ( cc = r ead( f d, buf , si zeof buf ) )
{
i f ( cc < 0)
er r exi t ( " echo r ead: %s\ n" , st r er r or ( er r no) ) ;
i f ( wr i t e( f d, buf , cc) < 0)
er r exi t ( " echo wr i t e: %s\ n" , st r er r or ( er r no) ) ;
}
r et ur n 0;
}

voi d r eaper ( i nt si g)
{
i nt st at us;

whi l e ( wai t 3( &st at us, WNOHANG, ( st r uct r usage *) 0) >= 0)
/ * empt y */ ;
}

Single-Process, Concurrent Servers (TCP)

Data-dri ven Processing
www.tenouk.com

- Arrival of data triggers processing.
- A message is typically a request.
- Server replies and awaits additional requests.
- If processing time is small, the requests may be possible to handle sequentially.
- Timesharing would be necessary only when the processing load is too high for sequential processing.
- Timesharing with multiple slaves is easier.

Using Select for Data-dri ven Processing

- A process calls select to wait for one (or more) of a collection of open files (or sockets) to be ready for
I/O.

i nt sel ect ( i nt n, f d_set *r eadf ds, f d_set *wr i t ef ds, f d_set *except f ds, st r uct t i meval
*t i meout ) ;

FD_CLR( i nt f d, f d_set *set ) ;
FD_I SSET( i nt f d, f d_set *set ) ;
FD_SET( i nt f d, f d_set *set ) ;
FD_ZERO( f d_set *set ) ;

- sel ect ( ) returns the number of fd's ready for I/O.
- FD_I SSET is used to determine which fd's are ready.
- sel ect ( ) returns 0 if the timer expires.
- sel ect ( ) returns -1 if there is an error.

An ECHO Server using a Single Process

- The following is a sample codes for Echo server using a single process.

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
char *ser vi ce = " echo" ;
st r uct sockaddr _i n f si n;
i nt msock;
f d_set r f ds;
f d_set af ds;
i nt al en;
i nt f d, nf ds;
msock = passi veTCP( ser vi ce, QLEN) ;

nf ds = get dt abl esi ze( ) ;
FD_ZERO( &af ds) ;
FD_SET( msock, &af ds) ;

whi l e ( 1) {
memcpy( &r f ds, &af ds, si zeof ( r f ds) ) ;

i f ( sel ect ( nf ds, &r f ds, ( f d_set *) 0, ( f d_set *) 0, ( st r uct t i meval *) 0) < 0)
er r exi t ( " sel ect : %s\ n" , st r er r or ( er r no) ) ;
i f ( FD_I SSET( msock, &r f ds) )
{
i nt ssock;

al en = si zeof ( f si n) ;
ssock = accept ( msock, ( st r uct sockaddr *) &f si n, &al en) ;
i f ( ssock < 0)
er r exi t ( " accept : %s\ n" , st r er r or ( er r no) ) ;
FD_SET( ssock, &af ds) ;
}
f or ( f d=0; f d < nf ds; ++f d)
i f ( f d ! = msock && FD_I SSET( f d, &r f ds) )
i f ( echo( f d) == 0)
{
( voi d) cl ose( f d) ;
FD_CLR( f d, &af ds) ;
}
}
}

i nt echo( i nt f d)
{
www.tenouk.com
char buf [ BUFSI Z] ;
i nt cc;

cc = r ead( f d, buf , si zeof buf ) ;
i f ( cc < 0)
er r exi t ( " echo r ead: %s\ n" , st r er r or ( er r no) ) ;
i f ( cc && wr i t e( f d, buf , cc) < 0)
er r exi t ( " echo wr i t e: %s\ n" , st r er r or ( er r no) ) ;
r et ur n cc;
}

Multiprotocol Servers

Why use multiple protocols in a server?

- Using separate UDP and TCP servers gives the system administrator more flexibility.
- Using separate servers result in 2 moderately simple servers.
- Using one server eliminates duplicate code simplifying software maintenance.
- Using one server reduces the number of active processes.

A Multiprotocol DAYTIME Server

- The following is a sample codes for Multiprotocol Daytime server.

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
char *ser vi ce = " dayt i me" ; / * ser vi ce name or por t number */
char buf [ LI NELEN+1] ; / * buf f er f or one l i ne of t ext */
st r uct sockaddr _i n f si n; / * t he r equest f r omaddr ess */
i nt al en; / * f r om- addr ess l engt h */
i nt t sock; / * TCP mast er socket */
i nt usock; / * UDP socket */
i nt nf ds;
f d_set r f ds; / * r eadabl e f i l e descr i pt or s */

t sock = passi veTCP( ser vi ce, QLEN) ;
usock = passi veUDP( ser vi ce) ;
/ * bi t number of max f d */
nf ds = MAX( t sock, usock) + 1;

FD_ZERO( &r f ds) ;

whi l e ( 1) {
FD_SET( t sock, &r f ds) ;
FD_SET( usock, &r f ds) ;

i f ( sel ect ( nf ds, &r f ds, ( f d_set *) 0, ( f d_set *) 0, ( st r uct t i meval *) 0) < 0)
er r exi t ( " sel ect er r or : %s\ n" , st r er r or ( er r no) ) ;
i f ( FD_I SSET( t sock, &r f ds) )
{
/ * TCP sl ave socket */
i nt ssock;
al en = si zeof ( f si n) ;
ssock = accept ( t sock, ( st r uct sockaddr *) &f si n, &al en) ;
i f ( ssock < 0)
er r exi t ( " accept f ai l ed: %s\ n" , st r er r or ( er r no) ) ;
dayt i me( buf ) ;
( voi d) wr i t e( ssock, buf , st r l en( buf ) ) ;
( voi d) cl ose( ssock) ;
}
i f ( FD_I SSET( usock, &r f ds) )
{
al en = si zeof ( f si n) ;
i f ( r ecvf r om( usock, buf , si zeof ( buf ) , 0, ( st r uct sockaddr *) &f si n, &al en) < 0)
er r exi t ( " r ecvf r om: %s\ n" , st r er r or ( er r no) ) ;
dayt i me( buf ) ;
( voi d) sendt o( usock, buf , st r l en( buf ) , 0, ( st r uct sockaddr *) &f si n, si zeof ( f si n) ) ;
}
}
}

i nt dayt i me( char buf [ ] )
{
char *ct i me( ) ;
t i me_t now;
www.tenouk.com

( voi d) t i me( &now) ;
spr i nt f ( buf , " %s" , ct i me( &now) ) ;
}


Multiservice Servers

Why combine services into one server?

- Fewer processes.
- Less memory.
- Less code duplication.
- Server complexity is really a result of accepting connections and handling concurrency.
- Having one server means the complex code does not need to be replicated.

Iterati ve Connectionless Server Design

- Server opens multiple UDP sockets each bound to a different port.
- Server keeps an array of function pointers to associate each socket with a service functions.
- Server uses select to determine which socket (port) to service next and calls the proper service function.

Iterati ve Connection-Oriented Server Design

- Server opens multiple passive TCP sockets each bound to a different port.
- Server keeps an array of function pointers to associate each socket with a service functions.
- Server uses select to determine which socket (port) to service next.
- When a connection is ready, server calls accept to start handling a connection.
- Server calls the proper service function.

Concurrent Connection-Oriented Server Design

- Master uses select to wait for connections over a set of passive TCP sockets.
- Master forks after accept.
- Slave handles communication with the client.

Single-Process Server Design

- Master uses select to wait for connections over a set of passive TCP sockets.
- After each accepts the new socket is added to the f d_set (s) as needed to handle client
communication.
- Complex if the client protocols are not trivial.

Invoking Separate Programs from a Server

- Master uses sel ect ( ) to wait for connections over a set of passive TCP sockets.
- Master forks after accept.
- Child process uses execve to start a slave program to handle client communication.
- Different protocols are separated making it simpler to maintain.
- Changes to a slave program can be implemented without restarting the master.

Multiservice, Multiprotocol Servers

- Master uses select to wait for connections over a set of passive TCP sockets.
- In addition the f d_set includes a set of UDP sockets awaiting client messages.
- If a UDP message arrives, the master calls a handler function which formulates and issues a reply.
- If a TCP connection is needed the master calls accept.
- For simpler TCP connections, the master can handle read and write requests iteratively.
- The master can also use select.
- Lastly the master can use fork and let the child handle the connection.

Code Example of Super Server

- The following is a sample codes for super server.
www.tenouk.com

st r uct ser vi ce {
char *sv_name;
char sv_useTCP;
i nt sv_sock;
i nt ( *sv_f unc) ( i nt ) ;
};

st r uct ser vi ce svent [ ] = {
{ " echo" , TCP_SERV, NOSOCK, TCPechod },
{ " char gen" , TCP_SERV, NOSOCK, TCPchar gend },
{ " dayt i me" , TCP_SERV, NOSOCK, TCPdayt i med },
{ " t i me" , TCP_SERV, NOSOCK, TCPt i med },
{ 0, 0, 0, 0 },
};

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
st r uct ser vi ce *psv, / * ser vi ce t abl e poi nt er */
*f d2sv[ NOFI LE] ; / * map f d t o ser vi ce poi nt er */
i nt f d, nf ds;
f d_set af ds, r f ds; / * r eadabl e f i l e descr i pt or s */

nf ds = 0;
FD_ZERO( &af ds) ;
f or ( psv = &svent [ 0] ; psv- >sv_name; ++psv)
{
i f ( psv- >sv_useTCP)
psv- >sv_sock = passi veTCP( psv- >sv_name, QLEN) ;
el se
psv- >sv_sock = passi veUDP( psv- >sv_name) ;
f d2sv[ psv- >sv_sock] = psv;
nf ds = MAX( psv- >sv_sock+1, nf ds) ;
FD_SET( psv- >sv_sock, &af ds) ;
}

( voi d) si gnal ( SI GCHLD, r eaper ) ;

whi l e ( 1) {
memcpy( &r f ds, &af ds, si zeof ( r f ds) ) ;
i f ( sel ect ( nf ds, &r f ds, ( f d_set *) 0, ( f d_set *) 0, ( st r uct t i meval *) 0) < 0)
{
i f ( er r no == EI NTR)
cont i nue;
er r exi t ( " sel ect er r or : %s\ n" , st r er r or ( er r no) ) ;
}
f or ( f d=0; f d<nf ds; ++f d)
{
i f ( FD_I SSET( f d, &r f ds) )
{
psv = f d2sv[ f d] ;
i f ( psv- >sv_useTCP)
doTCP( psv) ;
el se
psv- >sv_f unc( psv- >sv_sock) ;
}
}
}
}

/ * doTCP( ) - handl e a TCP ser vi ce connect i on r equest */
voi d doTCP( st r uct ser vi ce *psv)
{
/ * t he r equest f r omaddr ess */
st r uct sockaddr _i n f si n;
/ * f r om- addr ess l engt h */
i nt al en;
i nt f d, ssock;

al en = si zeof ( f si n) ;
ssock = accept ( psv- >sv_sock, ( st r uct sockaddr *) &f si n, &al en) ;
i f ( ssock < 0)
er r exi t ( " accept : %s\ n" , st r er r or ( er r no) ) ;
swi t ch ( f or k( ) )
{
case 0:
br eak;
case - 1:
www.tenouk.com
er r exi t ( " f or k: %s\ n" , st r er r or ( er r no) ) ;
def aul t :
( voi d) cl ose( ssock) ;
/ * par ent */
r et ur n;
}
/ * chi l d */
f or ( f d = NOFI LE; f d >= 0; - - f d)
i f ( f d ! = ssock) ( voi d) cl ose( f d) ;
exi t ( psv- >sv_f unc( ssock) ) ;
}

/ * r eaper ( ) - cl ean up zombi e chi l dr en */
voi d r eaper ( i nt si g)
{
i nt st at us;
whi l e( wai t 3( &st at us, WNOHANG, ( st r uct r usage *) 0) >= 0)
/ * empt y */ ;
}

Some Idea In Managing Server Concurrency

Concurrency vs Iteration

Making the decision

- Program design is vastly different.
- Programmer needs to decide early.
- Network and computer speeds change.
- Optimality is a moving target.
- Programmer must use insight based on experience to decide which is better.

Level of Concurrency

- Number of concurrent clients.
- Iterative means 1 client at a time.
- Unbounded concurrency allows flexibility.
- TCP software limits the number of connections.
- OS limits each process to a fixed number of open files.
- OS limits the number of processes.

Problems with Unbounded Concurrency

- OS can run out of resources such as memory, processes, sockets, buffers causing blocking, thrashing,
crashing...
- Demand for one service can inhibit others e.g. web server may prevent other use.
- Over-use can limit performance e.g. ftp server could be so slow that clients cancel requests wasting
time spent doing a partial transfer.

Cost of Concurrency

- Assuming a forking concurrent server, each connection requires time for a process creation (c).
- Each connection also requires some time for processing requests (p).
- Consider 2 requests arriving at the same time.
- Iterative server completes both at time 2p.
- Concurrent server completes both perhaps at time 2c+p.
- If p <2c the iterative server is faster.
- The situation can get worse with more requests.
- The number of active processes can exceed the CPU capacity.
- Servers with heavy loads generally try to dodge the process creation cost.

Process Pre-allocation to Limit Delays

- Master server process forks n times.
- The n slaves handle up to n clients.
- Operates like n iterative servers.
www.tenouk.com
- Due to child processes inheriting the parent's passive socket, the slaves can all wait in accept on the
same socket.
- For UDP, the slaves can all call recvfrom on the same socket.
- To avoid problems like memory leaks, the slaves can be periodically replaced.
- For UDP, bursts can overflow buffers causing data loss. Pre-allocation can limit this problem.

Dynamic Pre-allocation

- Pre-allocation can cause extra processing time if many slaves are all waiting on the same socket.
- If the server is busy, it can be better to have many slaves pre-allocated.
- If the server is idle, it can be better to have very few slaves pre-allocated.
- Some servers (Apache) adjust the level of concurrency according to service demand.

Delayed Allocation

- Rather than immediately forking, the master can quickly examine a request.
- It may be faster for some requests to handle them in the master rather than forking.
- Longer requests may be more appropriate to handle in a child process.
- If it is hard to quickly estimate processing time, the server can set a timer to expire after a small time
and then fork to let a child finish the request.

Client Concurrency

- Shorter Response Time.
- Increased Throughput.
- Concurrency Allows Better Control.
- Communicating with Multiple Servers.
- Achieving Concurrency with a Single Client Process.

------------------------Program Examples----------------------

DNS

- DNS stands for "Domain Name System" (for Windows implementation it is called Domain Name
Service). For socket it has three major components:

Domain name space and resource records: Specifications for a tree-structured name space and the
data associated with the names.
Name servers: Server programs that hold information about the domain tree structure and that set
information.
Resolvers: Programs that extract information from name servers in response to client requests.

- DNS used to translate the IP address to domain name and vice versa. This way, when someone enters:

telnet serv.google.com

- t el net can find out that it needs to connect() to let say, "198.137.240.92". To get these
information we can use gethostbyname():

#include <netdb.h>

struct hostent *gethostbyname(const char *name);

- As you see, it returns a pointer to a struct hostent, and struct hostent is shown below:

struct hostent
{
char *h_name;
char **h_aliases ;
int h_addrtype;
int h_length;
char **h_addr_list;
} ;

#define h_addr h_addr_list[0]

- And the descriptions:
www.tenouk.com

Member Description
h_name Official name of the host.
h_aliases A NULL-terminated array of alternate names for the host.
h_addrtype The type of address being returned; usually AF_INET.
h_length The length of the address in bytes.
h_addr_list
A zero-terminated array of network addresses for the host. Host
addresses are in Network Byte Order.
h_addr The first address in h_addr_list.

Table 40.1

- gethostbyname() returns a pointer to the filled struct hostent, or NULL on error but errno
is not set, h_errno is set instead.
- As said before in implementation we use Domain Name Service in Windows and BIND in Unix/Linux.
Here, we configure the Forward Lookup Zone for name to IP resolution and Reverse Lookup Zone for
the reverse.
- The following is a program example using the get host name( ) .

/ *****get i paddr . c ******/
/ ****a host name l ookup pr ogr amexampl e******/
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <er r no. h>
#i ncl ude <net db. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h >
#i ncl ude <ar pa/ i net . h>

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
st r uct host ent *h;

/ *er r or check t he command l i ne*/
i f ( ar gc ! = 2)
{
f pr i nt f ( st der r , " Usage: %s <domai n_name>\ n" , ar gv[ 0] ) ;
exi t ( 1) ;
}

/ *get t he host i nf o*/
i f ( ( h=get host byname( ar gv[ 1] ) ) == NULL)
{
her r or ( " get host byname( ) : " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " get host byname( ) i s OK. \ n" ) ;

pr i nt f ( " The host name i s: %s\ n" , h- >h_name) ;
pr i nt f ( " The I P Addr ess i s: %s\ n" , i net _nt oa( *( ( st r uct i n_addr *) h- >h_addr ) ) ) ;
pr i nt f ( " The addr ess l engt h i s: %d\ n" , h- >h_l engt h) ;

pr i nt f ( " Sni f f i ng ot her names. . . sni f f . . . sni f f . . . sni f f . . . \ n" ) ;
i nt j = 0;
d o
{
pr i nt f ( " An al i as #%d i s: %s\ n" , j , h- >h_al i ases[ j ] ) ;
j ++;
}
whi l e( h- >h_al i ases[ j ] ! = NULL) ;

pr i nt f ( " Sni f f i ng ot her I Ps. . . sni f f . . . . sni f f . . . sni f f . . . \ n" ) ;
i nt i = 0;
do
{
pr i nt f ( " Addr ess #%i i s: %s\ n" , i , i net _nt oa( *( ( st r uct i n_addr *) ( h- >h_addr _l i st [ i ] ) ) ) ) ;
i ++;
}
whi l e( h- >h_addr _l i st [ i ] ! = NULL) ;
r et ur n 0;
}

www.tenouk.com
- Compile and link the program.

[bodo@bakawali testsocket]$ gcc -g getipaddr.c -o getipaddr

- Run the program. Because of the server used in this testing is using public IP address, we can test it
querying the public domain such as www. yahoo. com:o).

[bodo@bakawali testsocket]$ ./getipaddr www.yahoo.com
The host name i s: www. yahoo. akadns. net
The I P Addr ess i s: 66. 94. 230. 50
The addr ess l engt h i s: 4
Sni f f i ng ot her names. . . sni f f . . . sni f f . . . sni f f . . .
An al i as #0 i s: www. yahoo. com
Sni f f i ng ot her I Ps. . . sni f f . . . . sni f f . . . sni f f . . .
Addr ess #0 i s: 66. 94. 230. 50
Addr ess #1 i s: 66. 94. 230. 36
Addr ess #2 i s: 66. 94. 230. 41
Addr ess #3 i s: 66. 94. 230. 34
Addr ess #4 i s: 66. 94. 230. 47
Addr ess #5 i s: 66. 94. 230. 32
Addr ess #6 i s: 66. 94. 230. 35
Addr ess #7 i s: 66. 94. 230. 45

- Again, running the program testing another domain.

[bodo@bakawali testsocket]$ ./getipaddr www.google.com
The host name i s: www. l . googl e. com
The I P Addr ess i s: 66. 102. 7. 104
The addr ess l engt h i s: 4
Sni f f i ng ot her names. . . sni f f . . . sni f f . . . sni f f . . .
An al i as #0 i s: www. googl e. com
Sni f f i ng ot her I Ps. . . sni f f . . . . sni f f . . . sni f f . . .
Addr ess #0 i s: 66. 102. 7. 104
Addr ess #1 i s: 66. 102. 7. 99
Addr ess #2 i s: 66. 102. 7. 147
[bodo@bakawali testsocket]$

- With gethostbyname(), you cant use perror() to print error message since errno is not used
instead, call herror().
- You simply pass the string that contains the machine name ("www. googl e. com") to
gethostbyname(), and then grab the information out of the returned struct hostent.
- The only possible weirdness might be in the printing of the IP address. Here, h- >h_addr is a
char*, but inet_ntoa() wants a struct in_addr passed to it. So we need to cast h-
>h_addr to a struct in_addr*, then dereference it to get the data.

Some Client-Server Background

- J ust about everything on the network deals with client processes talking to server processes and vice-
versa. For example take a t el net .
- When you telnet to a remote host on port 23 at client, a program on that server normally called
t el net d (telnet daemon), will respond. It handles the incoming telnet connection, sets you up with a
login prompt, etc. In Windows this daemon normally called a service. The daemon or service must be
running in order to do the communication.
- Note that the client-server pair can communicate using SOCK_STREAM, SOCK_DGRAM, or anything
else (as long as theyre using the same protocol). Some good examples of client-server pairs are
t el net / t el net d, f t p/ f t pd, or boot p/ boot pd. Every time you use f t p, theres a remote
program, f t pd that will serve you.
- Often, there will only be one server, and that server will handle multiple clients using fork() etc. The
basic routine is: server will wait for a connection, accept() it and fork() a child process to handle
it. The following program example is what our sample server does.

A Simple Stream Server Program Example

- What this server does is send the string "Thi s i s a t est st r i ng f r omser ver ! " out over a
stream connection.
www.tenouk.com
- To test this server, run it in one window and telnet to it from another window or run it in a server and
telnet to it from another machine with the following command.

telnet the_remote_hostname 3490

- Where t he_remote_hostname is the name of the machine youre running it on. The following is
the server source code:

/ *ser ver pr og. c - a st r eamsocket ser ver demo*/
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <uni st d. h>
#i ncl ude <er r no. h>
#i ncl ude <st r i ng. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h >
#i ncl ude <ar pa/ i net . h >
#i ncl ude <sys/ wai t . h>
#i ncl ude <si gnal . h>

/ * t he por t user s wi l l be connect i ng t o */
#def i ne MYPORT 3490
/ * how many pendi ng connect i ons queue wi l l hol d */
#def i ne BACKLOG 10

voi d si gchl d_handl er ( i nt s)
{
whi l e( wai t ( NULL) > 0) ;
}

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
/ *l i st en on sock_f d, new connect i on on new_f d*/
i nt sockf d, new_f d;
/ *my addr ess i nf or mat i on*/
st r uct sockaddr _i n my_addr ;
/ *connect or s addr ess i nf or mat i on*/
st r uct sockaddr _i n t hei r _addr ;
i nt si n_si ze;
st r uct si gact i on sa;
i nt yes = 1;

i f ( ( sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ) == - 1)
{
per r or ( " Ser ver - socket ( ) er r or l ol ! " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Ser ver - socket ( ) sockf d i s OK. . . \ n" ) ;

i f ( set sockopt ( sockf d, SOL_SOCKET, SO_REUSEADDR, &yes, si zeof ( i nt ) ) == - 1)
{
per r or ( " Ser ver - set sockopt ( ) er r or l ol ! " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Ser ver - set sockopt i s OK. . . \ n" ) ;

/ * host byt e or der */
my_addr . si n_f ami l y = AF_I NET;
/ * shor t , net wor k byt e or der */
my_addr . si n_por t = ht ons( MYPORT) ;
/ * aut omat i cal l y f i l l wi t h my I P*/
my_addr . si n_addr . s_addr = I NADDR_ANY;

pr i nt f ( " Ser ver - Usi ng %s and por t %d. . . \ n" , i net _nt oa( my_addr . si n_addr ) , MYPORT) ;

/ * zer o t he r est of t he st r uct */
memset ( &( my_addr . si n_zer o) , ' \ 0' , 8) ;

i f ( bi nd( sockf d, ( st r uct sockaddr *) &my_addr , si zeof ( st r uct sockaddr ) ) == - 1)
{
per r or ( " Ser ver - bi nd( ) er r or " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Ser ver - bi nd( ) i s OK. . . \ n" ) ;
www.tenouk.com

i f ( l i st en( sockf d, BACKLOG) == - 1)
{
per r or ( " Ser ver - l i st en( ) er r or " ) ;
exi t ( 1) ;
}
pr i nt f ( " Ser ver - l i st en( ) i s OK. . . Li st eni ng. . . \ n" ) ;

/ *cl ean al l t he dead pr ocesses*/
sa. sa_handl er = si gchl d_handl er ;
si gempt yset ( &sa. sa_mask) ;
sa. sa_f l ags = SA_RESTART;

i f ( si gact i on( SI GCHLD, &sa, NULL) == - 1)
{
per r or ( " Ser ver - si gact i on( ) er r or " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Ser ver - si gact i on( ) i s OK. . . \ n" ) ;

/ *accept ( ) l oop*/
whi l e( 1)
{
si n_si ze = si zeof ( st r uct sockaddr _i n) ;
i f ( ( new_f d = accept ( sockf d, ( st r uct sockaddr *) &t hei r _addr , &si n_si ze) ) == - 1)
{
per r or ( " Ser ver - accept ( ) er r or " ) ;
cont i nue;
}
el se
pr i nt f ( " Ser ver - accept ( ) i s OK. . . \ n" ) ;
pr i nt f ( " Ser ver - new socket , new_f d i s OK. . . \ n" ) ;
pr i nt f ( " Ser ver : Got connect i on f r om%s\ n" , i net _nt oa( t hei r _addr . si n_addr ) ) ;

/ * t hi s i s t he chi l d pr ocess */
i f ( ! f or k( ) )
{
/ * chi l d doesn t need t he l i st ener */
cl ose( sockf d) ;

i f ( send( new_f d, " Thi s i s a t est st r i ng f r omser ver ! \ n" , 37, 0) == - 1)
per r or ( " Ser ver - send( ) er r or l ol ! " ) ;
cl ose( new_f d) ;
exi t ( 0) ;
}
el se
pr i nt f ( " Ser ver - send i s OK. . . ! \ n" ) ;

/ * par ent doesn t need t hi s*/
cl ose( new_f d) ;
pr i nt f ( " Ser ver - new socket , new_f d cl osed successf ul l y. . . \ n" ) ;
}
r et ur n 0;
}

- Compile and link the program.

[ bodo@bakawal i t est socket ] $ gcc - g ser ver pr og. c - o ser ver pr og

- Run the program.

[ bodo@bakawal i t est socket ] $ . / ser ver pr og
Ser ver - socket ( ) sockf d i s OK. . .
Ser ver - set sockopt ( ) i s OK. . .
Ser ver - Usi ng 0. 0. 0. 0 and por t 3490. . .
Ser ver - bi nd( ) i s OK. . .
Ser ver - l i st en( ) i s OK. . . Li st eni ng. . .
Ser ver - si gact i on( ) i s OK. . .

[ 1] + St opped . / ser ver pr og

[ bodo@bakawal i t est socket ] $

- Verify that the program is running in the background. You may do this from another terminal.

www.tenouk.com
[ bodo@bakawal i t est socket ] $ bg
[ 1] + . / ser ver pr og &

- Verify that the program/process is listening on the specified port, waiting for connection.

[ bodo@bakawal i t est socket ] $ net st at - a | gr ep 3490
t cp 0 0 *: 3490 *: * LI STEN

- Again, verify that the program/process is listening, waiting for connection.

[ bodo@bakawal i t est socket ] $ ps aux | gr ep ser ver pr og
bodo 2586 0. 0 0. 2 2940 296 pt s/ 3 S 14: 04 0: 00 . / ser ver pr og
bodo 2590 0. 0 0. 5 5432 660 pt s/ 3 R+ 14: 04 0: 00 gr ep ser ver pr og

- Then, trying the telnet. Open another terminal, telnet itself with the specified port number. Here we
use the server name, bakawal i . When the string is displayed press the Escape character Ct r l +] ( ^]
). Then we have a real telnet session.

[bodo@bakawali testsocket]$ telnet bakawali 3490
Tr yi ng 203. 106. 93. 94. . .
Connect ed t o bakawal i . j mt i . gov. my ( 203. 106. 93. 94) .
Escape char act er i s ' ^] ' .
Thi s i s t he t est st r i ng f r omser ver !
^]
t el net > ?
Commands may be abbr evi at ed. Commands ar e:

cl ose cl ose cur r ent connect i on
l ogout f or ci bl y l ogout r emot e user and cl ose t he connect i on
di spl ay di spl ay oper at i ng par amet er s
mode t r y t o ent er l i ne or char act er mode ( ' mode ?' f or mor e)
open connect t o a si t e
qui t exi t t el net
send t r ansmi t speci al char act er s ( ' send ?' f or mor e)
set set oper at i ng par amet er s ( ' set ?' f or mor e)
unset unset oper at i ng par amet er s ( ' unset ?' f or mor e)
st at us pr i nt st at us i nf or mat i on
t oggl e t oggl e oper at i ng par amet er s ( ' t oggl e ?' f or mor e)
sl c change st at e of speci al char at er s ( ' sl c ?' f or mor e)
aut h t ur n on ( of f ) aut hent i cat i on ( ' aut h ?' f or mor e)
encr ypt t ur n on ( of f ) encr ypt i on ( ' encr ypt ?' f or mor e)
f or war d t ur n on ( of f ) cr edent i al f or war di ng ( ' f or war d ?' f or mor e)
z suspend t el net
! i nvoke a subshel l
envi r on change envi r onment var i abl es ( ' envi r on ?' f or mor e)
? pr i nt hel p i nf or mat i on
t el net >

- Type qui t to exit the session.

. . .
t el net > qui t
Connect i on cl osed.
[bodo@bakawali ~]$

- If we do not stop the server program/process (Ctrl+Z), at the server terminal the following messages
should be displayed. Press Ent er (Carriage Return) key back to the prompt.

[ bodo@bakawal i t est socket ] $ . / ser ver pr og
Ser ver - socket ( ) sockf d i s OK. . .
Ser ver - set sockopt ( ) i s OK. . .
Ser ver - Usi ng 0. 0. 0. 0 and por t 3490. . .
Ser ver - bi nd( ) i s OK. . .
Ser ver - l i st en( ) i s OK. . . Li st eni ng. . .
Ser ver - si gact i on( ) i s OK. . .
Ser ver - accept ( ) i s OK. . .
Ser ver - new socket , new_f d i s OK. . .
Ser ver : Got connect i on f r om203. 106. 93. 94
Ser ver - send( ) i s OK. . . !
Ser ver - new socket , new_f d cl osed successf ul l y. . .

- To stop the process just issue a normal ki l l command. Before that verify again.

www.tenouk.com
[bodo@bakawali testsocket]$ netstat -a | grep 3490
t cp 0 0 *: 3490 *: * LI STEN

[bodo@bakawali testsocket]$ ps aux | grep ./serverprog
bodo 3184 0. 0 0. 2 1384 324 pt s/ 3 S 23: 46 0: 00 . / ser ver pr og
bodo 3188 0. 0 0. 5 3720 652 pt s/ 3 R+ 23: 48 0: 00 gr ep . / ser ver pr og

[bodo@bakawali testsocket]$ kill -9 3184
[bodo@bakawali testsocket]$ netstat -a | grep 3490
[ 1] + Ki l l ed . / ser ver pr og

[bodo@bakawali testsocket]$

- The server program seems OK. Next section is a client program, cl i ent pr og. c that we will use to
test our server program, ser ver pr og. c.
- The sigaction() code is responsible for cleaning the zombie processes that appear as the
fork()ed child processes. You will get the message from this server by using the client program
example presented in the next section.

A Simple Stream Client Program Example

- This client will connect to the host that you specify in the command line, with port 3490. It will get the
string that the previous server sends. The following is the source code.

/ *** cl i ent pr og. c ****/
/ *** a st r eamsocket cl i ent demo ***/
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <uni st d. h>
#i ncl ude <er r no. h>
#i ncl ude <st r i ng. h>
#i ncl ude <net db. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <net i net / i n. h>
#i ncl ude <sys/ socket . h>

/ / t he por t cl i ent wi l l be connect i ng t o
#def i ne PORT 3490
/ / max number of byt es we can get at once
#def i ne MAXDATASI ZE 300

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d, numbyt es;
char buf [ MAXDATASI ZE] ;
st r uct host ent *he;
/ / connect or s addr ess i nf or mat i on
st r uct sockaddr _i n t hei r _addr ;

/ / i f no command l i ne ar gument suppl i ed
i f ( ar gc ! = 2)
{
f pr i nt f ( st der r , " Cl i ent - Usage: %s t he_cl i ent _host name\ n" , ar gv[ 0] ) ;
/ / j ust exi t
exi t ( 1) ;
}

/ / get t he host i nf o
i f ( ( he=get host byname( ar gv[ 1] ) ) == NULL)
{
per r or ( " get host byname( ) " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Cl i ent - The r emot e host i s: %s\ n" , ar gv[ 1] ) ;

i f ( ( sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ) == - 1)
{
per r or ( " socket ( ) " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Cl i ent - The socket ( ) sockf d i s OK. . . \ n" ) ;

www.tenouk.com
/ / host byt e or der
t hei r _addr . si n_f ami l y = AF_I NET;
/ / shor t , net wor k byt e or der
pr i nt f ( " Ser ver - Usi ng %s and por t %d. . . \ n" , ar gv[ 1] , PORT) ;
t hei r _addr . si n_por t = ht ons( PORT) ;
t hei r _addr . si n_addr = *( ( st r uct i n_addr *) he- >h_addr ) ;
/ / zer o t he r est of t he st r uct
memset ( &( t hei r _addr . si n_zer o) , ' \ 0' , 8) ;

i f ( connect ( sockf d, ( st r uct sockaddr *) &t hei r _addr , si zeof ( st r uct sockaddr ) ) == - 1)
{
per r or ( " connect ( ) " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Cl i ent - The connect ( ) i s OK. . . \ n" ) ;

i f ( ( numbyt es = r ecv( sockf d, buf , MAXDATASI ZE- 1, 0) ) == - 1)
{
per r or ( " r ecv( ) " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Cl i ent - The r ecv( ) i s OK. . . \ n" ) ;

buf [ numbyt es] = ' \ 0' ;
pr i nt f ( " Cl i ent - Recei ved: %s" , buf ) ;

pr i nt f ( " Cl i ent - Cl osi ng sockf d\ n" ) ;
cl ose( sockf d) ;
r et ur n 0;
}

- Compile and link the program.

[bodo@bakawali testsocket]$ gcc -g clientprog.c -o clientprog

- Run the program without argument.

[bodo@bakawali testsocket]$ ./clientprog
Cl i ent - Usage: . / cl i ent pr og t he_cl i ent _host name

- Run the program with server IP address or name as an argument. Here we use IP address.
- Make sure your previous ser ver pr og program is running. We will connect using the same server.
You can try running the server and client program at different machines.

[bodo@bakawali testsocket]$ ./clientprog 203.106.93.94

[bodo@bakawali testsocket]$ ./clientprog bakawali
Cl i ent - The r emot e host i s: bakawal i
Cl i ent - The socket ( ) sockf d i s OK. . .
Ser ver - Usi ng bakawal i and por t 3490. . .
Cl i ent - The connect ( ) i s OK. . .
Cl i ent - The r ecv( ) i s OK. . .
Cl i ent - Recei ved: Thi s i s t he t est st r i ng f r omser ver !
Cl i ent - Cl osi ng sockf d

- Verify the connection.

[bodo@bakawali testsocket]$ netstat -a | grep 3490
t cp 0 0 *: 3490 *: * LI STEN
t cp 0 0 bakawal i . j mt i . gov. my: 3490 bakawal i . j mt i . gov. my: 1358
TI ME_WAI T
[bodo@bakawali testsocket]$

- At servers console, we have the following messages.

[bodo@bakawali testsocket]$ ./serverprog
Ser ver - socket ( ) sockf d i s OK. . .
Ser ver - set sockopt ( ) i s OK. . .
Ser ver - Usi ng 0. 0. 0. 0 and por t 3490. . .
www.tenouk.com
Ser ver - bi nd( ) i s OK. . .
Ser ver - l i st en( ) i s OK. . . Li st eni ng. . .
Ser ver - si gact i on( ) i s OK. . .
Ser ver - accept ( ) i s OK. . .
Ser ver - new socket , new_f d i s OK. . .
Ser ver : Got connect i on f r om203. 106. 93. 94
Ser ver - send( ) i s OK. . . !
Ser ver - new socket , new_f d cl osed successf ul l y. . .

- Well, our server and client programs work! Here we run the server program and let it listens for
connection. Then we run the client program. They got connected!
- Notice that if you dont run the server before you run the client, connect() returns "Connect i on
r ef used" message as shown below.

[bodo@bakawali testsocket]$ ./clientprog bakawali
Cl i ent - The r emot e host i s: bakawal i
Cl i ent - The socket ( ) sockf d i s OK. . .
Ser ver - Usi ng bakawal i and por t 3490. . .
connect : Connect i on r ef used

Datagram Sockets: The Connectionless

- The following program examples use the UDP, the connectionless datagram. The sender pr og. c
(client) is sending a message to r ecei ver pr og. c (server) that acts as listener.

/ *r ecei ver pr og. c - a ser ver , dat agr amsocket s*/
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <uni st d. h>
#i ncl ude <er r no. h>
#i ncl ude <st r i ng. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h>
#i ncl ude <ar pa/ i net . h>
/ * t he por t user s wi l l be connect i ng t o */
#def i ne MYPORT 4950
#def i ne MAXBUFLEN 500

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d;
/ * my addr ess i nf or mat i on * /
st r uct sockaddr _i n my_addr ;
/ * connect or s addr ess i nf or mat i on */
st r uct sockaddr _i n t hei r _addr ;
i nt addr _l en, numbyt es;
char buf [ MAXBUFLEN] ;

i f ( ( sockf d = socket ( AF_I NET, SOCK_DGRAM, 0) ) == - 1)
{
per r or ( " Ser ver - socket ( ) sockf d er r or l ol ! " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Ser ver - socket ( ) sockf d i s OK. . . \ n" ) ;

/ * host byt e or der */
my_addr . si n_f ami l y = AF_I NET;
/ * shor t , net wor k byt e or der */
my_addr . si n_por t = ht ons( MYPORT) ;
/ * aut omat i cal l y f i l l wi t h my I P */
my_addr . si n_addr . s_addr = I NADDR_ANY;
/ * zer o t he r est of t he st r uct */
memset ( &( my_addr . si n_zer o) , ' \ 0' , 8) ;

i f ( bi nd( sockf d, ( st r uct sockaddr *) &my_addr , si zeof ( st r uct sockaddr ) ) == - 1)
{
per r or ( " Ser ver - bi nd( ) er r or l ol ! " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Ser ver - bi nd( ) i s OK. . . \ n" ) ;

addr _l en = si zeof ( st r uct sockaddr ) ;
www.tenouk.com

i f ( ( numbyt es = r ecvf r om( sockf d, buf , MAXBUFLEN- 1, 0, ( st r uct sockaddr *) &t hei r _addr ,
&addr _l en) ) == - 1)
{
per r or ( " Ser ver - r ecvf r om( ) er r or l ol ! " ) ;
/ *I f somet hi ng wr ong, j ust exi t l ol . . . */
exi t ( 1) ;
}
el se
{
pr i nt f ( " Ser ver - Wai t i ng and l i st eni ng. . . \ n" ) ;
pr i nt f ( " Ser ver - r ecvf r om( ) i s OK. . . \ n" ) ;
}

pr i nt f ( " Ser ver - Got packet f r om%s\ n" , i net _nt oa( t hei r _addr . si n_addr ) ) ;
pr i nt f ( " Ser ver - Packet i s %d byt es l ong\ n" , numbyt es) ;
buf [ numbyt es] = ' \ 0' ;
pr i nt f ( " Ser ver - Packet cont ai ns \ " %s\ " \ n" , buf ) ;

i f ( cl ose( sockf d) ! = 0)
pr i nt f ( " Ser ver - sockf d cl osi ng f ai l ed! \ n" ) ;
el se
pr i nt f ( " Ser ver - sockf d successf ul l y cl osed! \ n" ) ;
r et ur n 0;
}

- Compile and link the program.

[bodo@bakawali testsocket]$ gcc -g receiverprog.c -o receiverprog

- Run the program, and then verify that it is running in background, start listening, waiting for
connection.

[bodo@bakawali testsocket]$ ./receiverprog
Ser ver - socket ( ) sockf d i s OK. . .
Ser ver - bi nd( ) i s OK. . .

[ 1] + St opped . / r ecei ver pr og
[bodo@bakawali testsocket]$ bg
[ 1] + . / r ecei ver pr og &
[bodo@bakawali testsocket]$ netstat -a | grep 4950
udp 0 0 *: 4950 *: *
[bodo@bakawali testsocket]$

- This is UDP server, trying telnet to this server will fail because telnet uses TCP instead of UDP.

[bodo@bakawali testsocket]$ telnet 203.106.93.94 4950
Tr yi ng 203. 106. 93. 94. . .
t el net : connect t o addr ess 203. 106. 93. 94: Connect i on r ef used
t el net : Unabl e t o connect t o r emot e host : Connect i on r ef used
[bodo@bakawali testsocket]$

- Notice that in our call to socket() were using SOCK_DGRAM. Also, note that theres no need to
listen() or accept(). The following is the source code for sender pr og. c (the client).

/ *sender pr og. c - a cl i ent , dat agr am*/
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <uni st d. h>
#i ncl ude <er r no. h>
#i ncl ude <st r i ng. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h >
#i ncl ude <ar pa/ i net . h>
#i ncl ude <net db. h>
/ * t he por t user s wi l l be connect i ng t o */
#def i ne MYPORT 4950

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d;
/ * connect or s addr ess i nf or mat i on */
www.tenouk.com
st r uct sockaddr _i n t hei r _addr ;
st r uct host ent *he;
i nt numbyt es;

i f ( ar gc ! = 3)
{
f pr i nt f ( st der r , " Cl i ent - Usage: %s <host name> <message>\ n" , ar gv[ 0] ) ;
exi t ( 1) ;
}
/ * get t he host i nf o */
i f ( ( he = get host byname( ar gv[ 1] ) ) == NULL)
{
per r or ( " Cl i ent - get host byname( ) er r or l ol ! " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Cl i ent - get host name( ) i s OK. . . \ n" ) ;

i f ( ( sockf d = socket ( AF_I NET, SOCK_DGRAM, 0) ) == - 1)
{
per r or ( " Cl i ent - socket ( ) er r or l ol ! " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Cl i ent - socket ( ) sockf d i s OK. . . \ n" ) ;

/ * host byt e or der */
t hei r _addr . si n_f ami l y = AF_I NET;
/ * shor t , net wor k byt e or der */
pr i nt f ( " Usi ng por t : 4950\ n" ) ;
t hei r _addr . si n_por t = ht ons( MYPORT) ;
t hei r _addr . si n_addr = *( ( st r uct i n_addr *) he- >h_addr ) ;
/ * zer o t he r est of t he st r uct */
memset ( &( t hei r _addr . si n_zer o) , ' \ 0' , 8) ;

i f ( ( numbyt es = sendt o( sockf d, ar gv[ 2] , st r l en( ar gv[ 2] ) , 0, ( st r uct sockaddr *) &t hei r _addr ,
si zeof ( st r uct sockaddr ) ) ) == - 1)
{
per r or ( " Cl i ent - sendt o( ) er r or l ol ! " ) ;
exi t ( 1) ;
}
el se
pr i nt f ( " Cl i ent - sendt o( ) i s OK. . . \ n" ) ;

pr i nt f ( " sent %d byt es t o %s\ n" , numbyt es, i net _nt oa( t hei r _addr . si n_addr ) ) ;

i f ( cl ose( sockf d) ! = 0)
pr i nt f ( " Cl i ent - sockf d cl osi ng i s f ai l ed! \ n" ) ;
el se
pr i nt f ( " Cl i ent - sockf d successf ul l y cl osed! \ n" ) ;
r et ur n 0;
}

- Compile and link the program.

[bodo@bakawali testsocket]$ gcc -g senderprog.c -o senderprog

- Run the program without arguments.

[bodo@bakawali testsocket]$ ./senderprog
Cl i ent - Usage: . / sender pr og <host name> <message>

- Run the program with arguments.

[bodo@bakawali testsocket]$ ./senderprog 203.106.93.94 "Testing UDP datagram message from client"
Cl i ent - get host name( ) i s OK. . .
Cl i ent - socket ( ) sockf d i s OK. . .
Usi ng por t : 4950
Ser ver - Wai t i ng and l i st eni ng. . .
Ser ver - r ecvf r om( ) i s OK. . .
Ser ver - Got packet f r om203. 106. 93. 94
Ser ver - Packet i s 42 byt es l ong
Ser ver - Packet cont ai ns " Test i ng UDP dat agr ammessage f r omcl i ent "
Ser ver - sockf d successf ul l y cl osed!
Cl i ent - sendt o( ) i s OK. . .
www.tenouk.com
sent 42 byt es t o 203. 106. 93. 94
Cl i ent - sockf d successf ul l y cl osed!
[ 1] + Done . / r ecei ver pr og
[bodo@bakawali testsocket]$

- Here, we test the UDP server and the client using the same machine. Make sure there is no restriction
such as permission etc. for the user that run the programs.
- To make it really real, may be you can test these programs by running r ecei ver pr og on some
machine, and then run sender pr og on another. If there is no error, they should communicate.
- If sender pr og calls connect() and specifies the r ecei ver pr ogs address then the
sender pr og may only sent to and receive from the address specified by connect().
- For this reason, you dont have to use sendto() and recvfrom(); you can simply use send()
and recv().

Blocking

- In a simple word 'block' means sleep but in a standby mode. You probably noticed that when you run
r ecei ver pr og, previously, it just sits there until a packet arrives.
- What happened is that it called recvfrom(), there was no data, and so recvfrom() is said to
"block" (that is, sleep there) until some data arrives. The socket functions that can block are:

accept ( )
r ead( )
r eadv( )
r ecv( )
r ecvf r om( )
r ecvmsg( )
send( )
sendmsg( )
sendt o( )
wr i t e( )
wr i t ev( )

- The reason they can do this is because theyre allowed to. When you first create the socket descriptor
with socket(), the kernel sets it to blocking.
- If you dont want a socket to be blocking, you have to make a call to fcntl() something like the
following:

#i ncl ude <uni st d. h>
#i ncl ude <f cnt l . h>
. . .
. . .
sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ;
f cnt l ( sockf d, F_SETFL, O_NONBLOCK) ;
. . .
. . .

- By setting a socket to non-blocking, you can effectively 'poll' the socket for information. If you try to
read from a non-blocking socket and theres no data there, its not allowed to block, it will return -1
and errno will be set to EWOULDBLOCK.
- Generally speaking, however, this type of polling is a bad idea. If you put your program in a busy-wait
looking for data on the socket, youll suck up CPU time.
- A more elegant solution for checking to see if theres data waiting to be read comes in the following
section on select().

Using select() for I/O multiplexing

- One traditional way to write network servers is to have the main server block on accept ( ) , waiting
for a connection. Once a connection comes in, the server f or k( ) s, then the child process handles the
connection and the main server is able to service new incoming requests.
- With sel ect ( ) , instead of having a process for each request, there is usually only one process that
multiplexes all requests, servicing each request as much as it can.
- So one main advantage of using sel ect ( ) is that your server will only require a single process to
handle all requests. Thus, your server will not need shared memory or synchronization primitives for
different tasks to communicate.
www.tenouk.com
- As discussed before we can use the non-blocking sockets functions but it is CPU intensive.
- One major disadvantage of using sel ect ( ) , is that your server cannot act like there's only one client,
like with a f or k( ) 'ing solution. For example, with a f or k( ) 'ing solution, after the server f or k( ) s,
the child process works with the client as if there was only one client in the universe, the child does not
have to worry about new incoming connections or the existence of other sockets.
- With sel ect ( ) , the programming isn't as transparent. The prototype is as the following:
#i ncl ude <sys/ t i me. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <uni st d. h>

i nt sel ect ( i nt numf ds, f d_set *r eadf ds, f d_set *wr i t ef ds, f d_set
*except f ds, st r uct t i meval *t i meout ) ;
- The function monitors "sets" of file descriptors; in particular readfds, writefds, and
exceptfds. If you want to see if you can read from standard input and some socket descriptor,
sockfd, just add the file descriptors 0 and sockfd to the set readfds.
- The parameter numfds should be set to the values of the highest file descriptor plus one. In this
example, it should be set to sockfd+1, since it is assuredly higher than standard input that is 0.
- When select() returns, readfds will be modified to reflect which of the file descriptors you have
selected which is ready for reading. You can test them with the macro FD_ISSET() listed below.
- Let see how to manipulate these sets. Each set is of the type fd_set. The following macros operate
on this type:

FD_ZERO(fd_set *set) clears a file descriptor set.
FD_SET(int fd, fd_set *set) adds fd to the set.
FD_CLR(int fd, fd_set *set) removes fd from the set.
FD_ISSET(int fd, fd_set *set) tests to see if fd is in the set.

- sel ect ( ) works by blocking until something happens on a file descriptor/socket. The 'something' is
the data coming in or being able to write to a file descriptor, you tell sel ect ( ) what you want to be
woken up by. How do you tell it? You fill up an f d_set structure with some macros.
- Most sel ect ( ) based servers look quite similar:

Fill up an f d_set structure with the file descriptors you want to know when data comes in on.
Fill up an f d_set structure with the file descriptors you want to know when you can write on.
Call sel ect ( ) and block until something happens.
Once sel ect ( ) returns, check to see if any of your file descriptors was the reason you woke
up. If so, 'service' that file descriptor in whatever particular way your server needs to (i.e. read in
a request for a Web page).
Repeat this process forever.

- Sometimes you dont want to wait forever for someone to send you some data. Maybe every 60
seconds you want to print something like "Pr ocessi ng. . . " to the terminal even though nothing has
happened.
- The t i meval structure allows you to specify a timeout period. If the time is exceeded and
select() still hasnt found any ready file descriptors, itll return, so you can continue processing.
- The struct timeval has the following fields:

struct timeval
{
int tv_sec; /* seconds */
int tv_usec; /* microseconds */
};

- J ust set tv_sec to the number of seconds to wait, and set tv_usec to the number of microseconds to
wait. There are 1,000,000 microseconds in a second. Also, when the function returns, timeout
might be updated to show the time still remaining.
- Standard UNIX time slice is around 100 milliseconds, so you might have to wait that long no matter
how small you set your struct timeval.
- If you set the fields in your struct timeval to 0, select() will timeout immediately,
effectively polling all the file descriptors in your sets. If you set the parameter timeout to NULL, it
will never timeout, and will wait until the first file descriptor is ready.
- Finally, if you dont care about waiting for a certain set, you can just set it to NULL in the call to
select().
- The following code snippet waits 5.8 seconds for something to appear on standard input.
www.tenouk.com

/ *sel ect cp. c - a sel ect ( ) demo*/
#i ncl ude <st di o. h>
#i ncl ude <sys/ t i me. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <uni st d. h>
/ * f i l e descr i pt or f or st andar d i nput */
#def i ne STDI N 0

i nt mai n( i nt ar gc, char *ar gv[ ] )
{
st r uct t i meval t val ;
f d_set r eadf ds;
t val . t v_sec = 5;
t val . t v_usec = 800000;

FD_ZERO( &r eadf ds) ;
FD_SET( STDI N, &r eadf ds) ;
/ * don t car e about wr i t ef ds and except f ds: */
sel ect ( STDI N+1, &r eadf ds, NULL, NULL, &t val ) ;
i f ( FD_I SSET( STDI N, &r eadf ds) )
pr i nt f ( " A key was pr essed l or ! \ n" ) ;
el se
pr i nt f ( " Ti med out l or ! . . . \ n" ) ;
r et ur n 0;
}

- Compile and link the program. Make sure there is no error :o).

[bodo@bakawali testsocket]$ gcc -g selectcp.c -o selectcp

- Run the program and then press k.

[bodo@bakawali testsocket]$ ./selectcp
k
A key was pr essed l or !

- Run the program and just leave it.

[bodo@bakawali testsocket]$ ./selectcp
Ti med out l or ! . . .

- If youre on a line buffered terminal, the key you hit should be RETURN or it will time out anyway.
- Now, some of you might think this is a great way to wait for data on a datagram socket and you are
right: it might be. Some Unices can use sel ect ( ) in this manner, and some cant. You should see
what your local man page says on the matter if you want to attempt it.
- Some Unices update the time in your struct timeval to reflect the amount of time still remaining
before a timeout. But others do not. Dont rely on that occurring if you want to be portable. Use
gettimeofday() if you need to track time elapsed.
- When a socket in the r ead set closes the connection, select() returns with that socket descriptor
set as "ready to read". When you actually do recv() from it, recv() will return 0. Thats how you
know the client has closed the connection.
- If you have a socket that is listen()ing, you can check to see if there is a new connection by putting
that sockets file descriptor in the readfds set.

Continue on next ModuleMore concept and program examples

-----------------------------------------End socket Part II-----------------------------------------
www. t enouk. com

Further reading and digging:

1. Check the best selling C/C++, Networking, Linux and Open Source books at Amazon.com.
www.tenouk.com

You might also like