Professional Documents
Culture Documents
We assume that when the client's data arrives, the server is temporarily busy, so the data is
added to the socket receive buffer by its TCP.
FIN is also added to the socket receive buffer. By default, the client's close returns
immediately. The client's close can return before the server reads the remaining data in its
socket receive buffer.
It is possible for the server host to crash before the server application reads this remaining
data.
The client can set the SO_LINGER socket option, specifying some positive linger time.
When this occurs, the client's close does not return until all the client's data and its FIN
have been acknowledged by the server TCP.
Figure . close with SO_LINGER socket option set and l_linger a positive value.
The basic principle here is that a successful return from close, with the SO_LINGER socket
option set, only tells us that the data we sent have been acknowledged by the peer TCP.
This does not tell us whether the peer application has read the data.
If we do not set the SO_LINGER socket option, we do not know whether the peer TCP has
acknowledged the data.
One way for the client to know that the server has read its data is to call shutdown (with a
second argument of SHUT_WR) instead of close and wait for the peer to close its end of
the connection.
Figure. Using shutdown to know that peer has received our data.
SO_LINGER socket option is set, the return can occur at three different times:
1. close returns immediately, without waiting at all
2. close lingers until the ACK of our FIN is received.
3. shutdown followed by a read waits until we receive the peer's FIN.
The above fig. shows a timeline of the typical scenario that takes place for a UDP
client/server exchange.
recvfrom and sendto function
These two functions are similar to the standard read and write functions, but three
additional arguments are required.
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, struct sockaddr *from,
socklen_t *addrlen);
ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags, const struct sockaddr
*to, socklen_t addrlen);
Both return: number of bytes read or written if OK, –1 on error
sockfd refers to an open socket descriptor.
buff is a pointer to buffer send from or read into.
nbytes number of bytes to read or write.
flags is either 0 or is formed by logically OR’ing one or more of the constants.
from points to the socket address structure filled by recvfrom function, with the protocol
address of who sent the data.
to points to socket address structure containing the protocol address of where the data is to
be sent.
addrlen contains the size of the socket address structure.
8. UDP Echo server
This program demonstrates a simple UDP server. It will receive one line of text; echo that
line back to the client and stops
Figure: Simple echo client/server using UDP.
#include "unp.h"
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(sockfd, (SA *) &servaddr, sizeof(servaddr));
dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
}
Create UDP socket, bind server's well-known port
We create a UDP socket by specifying the second argument to socket as
SOCK_DGRAM. The function dg_echo is called to perform server processing.
UDP Echo Server: dg_echo Function
#include "unp.h"
void dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for ( ; ; )
{
len = clilen;
n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
sendto(sockfd, mesg, n, 0, pcliaddr, len);
}
}
Read datagram, echo back to sender
This function is a simple loop that reads the next datagram arriving at the server's port
using recvfrom and sends it back using sendto.
Difference between TCP and UDP
UDP function never terminates. Since UDP is a connectionless protocol, there is nothing
like an EOF as we have with TCP.
Most TCP servers are concurrent and most UDP servers are iterative.
Each UDP socket has a receive buffer and each datagram that arrives for this socket is
placed in that socket receive buffer. When the process calls recvfrom, the next datagram from the
buffer is returned to the process in a first-in, first-out (FIFO) order. This way, if multiple
datagrams arrive for the socket before the process can read what's already queued for the socket,
the arriving datagrams are just added to the socket receive buffer. But, this buffer has a limited
size.
Figure: Summary of TCP client/server with two clients.
There are two connected sockets and each of the two connected sockets on the server host has its
own socket receive buffer.
Figure: Summary of UDP client/server with two clients.
There is only one server process and it has a single socket on which it receives all
arriving datagrams and sends all responses. That socket has a receive buffer into which all
arriving datagrams are placed.
9. UDP echo client
#include "unp.h"
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if(argc != 2)
err_quit("usage: udpcli <IPaddress>");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));
exit(0);
}
UDP Echo Client: dg_cli Function
#include "unp.h"
void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
while (fgets(sendline, MAXLINE, fp) != NULL)
{
sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
}
There are four steps in the client processing loop:
i. Read a line from standard input using fgets
ii. Send the line to the server using sendto
iii. Read back the server's echo using recvfrom
iv. Print the echoed line to standard output using fputs.
10. Multiplexing TCP and UDP sockets
We can combine the TCP echo server with the UDP echo server into a single server that
uses select to multiplex a TCP and UDP socket.
The code for the implementation of server that handles both TCP and UDP data is given
below.
#include “unp.h”
int main(int argc, char **argv)
{
int listenfd, connfd, udpfd, nready, maxfdp1;
pid_t childpid;
socketlen_t len;
char msg[MAXLINE];
ssize_t n;
fd_set rset;
const int on = 1;
struct sockaddr_in servaddr, cliaddr;
void sig_chld(int);
/* Create listening TCP Socket*/
listenfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
listen(listenfd,LISTENQ);
/* Create UDP Socket*/
udpfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
bind(udpfd,(SA*)&servaddr,sizeof(servaddr));
/*establish signal handler for SIGCHLD*/
signal(SIGCHLD, sig_chld);
/*prepare for select*/
FD_ZERO(&rset);
maxfdp1 = max(listenfd,udpfd)+1;
for(; ;)
{
/*call select*/
FD_SET(listenfd,&rset);
FD_SET(udpfd,&rset);
if((nready=select(maxfdp1,&rset,NULL,NULL,NULL))<0);
if(errno==EINTR)
continue;
else
err_sys(“Select Error”);
}
/* handle new client connection*/
if(FD_ISSET(listedfd,&rset))
{
len = sizeof(cliaddr);
connfd = accept(listenfd, (SA*)&cliaddr,&len);
if((childpid=fork( ))==0)
{
close(listenfd);
str_echo(connfd);
exit(0);
}
close(connfd);
}
/* handle arrival of data*/
if(FD_ISSET(udpfd,&rset))
{
len = sizeof(cliaddr);
n=recvfrom(udpfd, msg, MAXLINE, 0, (SA*)&cliaddr, &len);
sendto(udpfd,msg,n,0,(SA*)&cliaddr,len);
}
}
}
Create listening TCP socket
A listening TCP socket is created that is bound to the server's well-known port. We set
the SO_REUSEADDR socket option in case connections exist on this port.
Create UDP socket
A UDP socket is also created and bound to the same port. Even though the same port is
used for TCP and UDP sockets, there is no need to set the SO_REUSEADDR socket option
before this call to bind, because TCP ports are independent of UDP ports.
Establish signal handler for SIGCHLD
A signal handler is established for SIGCHLD because TCP connections will be handled
by a child process.
Prepare for select
We initialize a descriptor set for select and calculate the maximum of the two descriptors
for which we will wait.
Call select
We call select, waiting only for readability on the listening TCP socket or readability on
the UDP socket. Since our sig_chld handler can interrupt our call to select, we handle an error of
EINTR.
Handle new client connection
We accept a new client connection when the listening TCP socket is readable, fork a
child, and call our str_echo function in the child.
Handle arrival of datagram
If the UDP socket is readable, a datagram has arrived. We read it with recvfrom and send
it back to the client with sendto.
11. Domain Name System
The DNS is used primarily to map between hostnames and IP addresses. A hostname can
be either a simple name, such as solaris or freebsd, or a fully qualified domain name '(FQDN),
such as solaris.unpbook.com.
Technically, an FQDN is also called an absolute name and must end with a period, but
users often omit the ending period.
The DNS is the service used to convert human readable names of hosts to IP addresses.
Host names are not case sensitive and can contain alphabetic or numeric letters or the hyphen.
Avoid the underscore. A FQDN consists of the host name plus domain name as in the following
example: computername.domain.com.
Resource Records
Entries in the DNS are known as resource records (RRs). There are only a few types of
RRs that we are interested in.
A - An A record maps a hostname into a 32-bit IPv4 address.
AAAA - A AAAA record, called a "quad A" record, maps a hostname into a 128-bit
IPv6 address. The term "quad A" was chosen because a 128-bit address is four times larger
than a 32-bit address.
PTR - PTR records (called "pointer records") map IP addresses into hostnames. For an
IPv4 address, then 4 bytes of the 32-bit address are reversed, each byte is converted to its
decimal ASCII value (0–255), and in-addr.arpa is the appended. The resulting string is used
in the PTR query.
MX An MX record specifies a host to act as a "mail exchanger" for the specified host.
CNAME CNAME stands for "canonical name." A common use is to assign CNAME
records for common services, such as ftp and www. If people use these service names
instead of the actual hostnames, it is transparent when a service is moved to another host.
Resolvers and Name Servers
Organizations run one or more name servers, often the program known as BIND
(Berkeley Internet Name Domain). Applications such as the clients and servers contact a DNS
server by calling functions in a library known as the resolver. The common resolver functions are
gethostbyname and gethostbyaddr. The former maps a hostname into its IPv4 addresses, and the
latter does the reverse mapping.
The below fig. shows a typical arrangement of applications, resolvers, and name servers.
We now write the application code. On some systems, the resolver code is contained in a system
library and is link-edited into the application when the application is built. On others, there is a
centralized resolver daemon that all applications share, and the system library code performs
RPCs to this daemon. In either case, application code calls the resolver code using normal
function calls, typically calling the functions gethostbyname and gethostbyaddr.
The resolver code reads its system-dependent configuration files to determine the
location of the organization's name servers.
Figure. Typical arrangement of clients, resolvers, and name servers.
The resolver sends the query to the local name server using UDP. If the local name server
does not know the answer, it will normally query other name servers across the Internet, also
using UDP. If the answers are too large to fit in a UDP packet, the resolver will automatically
switch to TCP.
12. gethostbyname function
Host computers are normally known by human-readable names. Most applications should
deal with names, not addresses.
The most basic function that looks up a hostname is gethostbyname. If successful, it returns a
pointer to a hostent structure that contains all the IPv4 addresses for the host. However, it is
limited in that it can only return IPv4 addresses.
#include <netdb.h>
struct hostent *gethostbyname (const char *hostname);
Returns: non-null pointer if OK,NULL on error with h_errno set
The non-null pointer returned by this function points to the following hostent structure:
struct hostent
{
char *h_name; /* official (canonical) name of host */
char **h_aliases; /* pointer to array of pointers to alias names */
int h_addrtype; /* host address type: AF_INET */
int h_length; /* length of address: 4 */
char **h_addr_list; /* ptr to array of ptrs with IPv4 addrs */
};
h_name points to the character string that contains the name of the host.
h_aliases is a pointer to a NULL terminated list of pointers, each of which points to a
character string that represents an alternative name for the host.
h_addrtype contains the address type of the host.
h_length contains the address length.
h_addr_list is a pointer to a NULL terminated list of pointers, each of which points to a
network address for the host, in network byte order.
In terms of the DNS, gethostbyname performs a query for an A record. This function can return
only IPv4 addresses.
The fig. shows the arrangement of the hostent structure and the information that it points
to assuming the hostname that is looked up has two alias names and three IPv4 addresses. Of
these fields, the official hostname and all the aliases are null-terminated C strings.
Figure . hostent structure and the information it contains.
13. IPv6 support in DNS
RES_USE_INET6 Resolver Option
We can use RES_USE_INET6 resolver that we want IPv6 address returned by
gethostbyname.
Three ways to set in
i. In the application program, add:
#include<resolv.h>
res.init();
res.option|=RES_USE_INET6;
ii. Set environment variable: export RES_OPTIONS = inet6
iii. Set options inet6 to be contained in the file.
#include<netdb.h>
struct hostent *gethostbyname2*(const char *hostname, int family);
Argument
const char *hostname: host name.
int family: AF_INET 0R AF_INET6
RES_USE_INET6 Option Off (gethostbyname)
Search for A records. If found, return IPv4 address (h_length=4). Else error
This provides backward compatibility or all existing IPv4 application.
RES_USE_INET6 ON (gethostbyname)
Search for AAAA records. If found, return IPv6 address (h_length=16).
Else search for A records. If found, return IPv4 mapped IPv6 address. Else error.
RES_USE_INET6 Option OFF (gethostbyname2)
gethostbyname2 (host, AF_INET): Search for A records, If found, return IPv4 addresses.
Else error.
gethostbyname2 (host, AF_INET6): Search for AAAA records, If found, return IPv6
addresses. Else error.
RES_USE_INET6 Option ON (gethostbyname2)
gethostbyname2 (host, AF_INET): Search for A records, If found, return IPv4 mapped
IPv6 addresses (h_length=16). Else error.
gethostbyname2 (host, AF_INET6): Search for AAAA records, If found, return IPv6
addresses (h_length=16). Else error.
14. gethostbyaddr function
getservbyport function
The function gethostbyaddr takes a binary IPv4 address and tries to find the hostname
corresponding to that address. This is the reverse of gethostbyname.
#include <netdb.h>
struct hostent *gethostbyaddr (const char *addr, socklen_t len, int family);
Returns: non-null pointer if OK, NULL on error with h_errno set
This function returns a pointer to the hostent structure. The field of interest in this
structure is normally h_name, the canonical hostname.
The addr argument is not a char*, but is really a pointer to an in_addr structure containing the
IPv4 address. len is the size of this structure. The family argument is AF_INET.
15. getservbyname and getservbyport function.
The getservbyname( ) function searches the database and finds an entry which matches
the specified service name and the specified protocol, opening a connection to the database if
necessary.
#include <netdb.h>
struct servent *getservbyname (const char *servname, const char *protoname);
Returns: non-null pointer if OK, NULL on error
servname
The pointer to the character string that contains the name of the service for which
information is to be retrieved ( for example, telnet).
protoname
The pointer to the character string that contains the name of the protocol that further
qualifies the search criteria. For example, if the servname is telnet, and the protoname is tcp,
then the call will return the telnet server that uses the TCP protocol.
This function returns a pointer to the following structure: The structure struct servent is
defined in <netdb>
.struct servent
{
char *s_name; /* official service name */
char **s_aliases; /* alias list */
int s-port; /* port number, network-byte order */
char *s_proto; /* protocol to use */
};
s_name points to the character string that contains the name of the service.
s_aliases is a pointer to a NULL terminated array of alternate names for the service.
s_port is the port number assigned to the service
s_proto is the protocol being used by the service.
getservbyport function
The getservbyport( ) function searches the database and finds an entry which matches
the specified port number and the specified protocol, opening a connection to the database if
necessary.
#include <netdb.h>
struct servent *getservbyport (int port, const char *protoname);
Returns: non-null pointer if OK, NULL on error
port
The port number for which service information is to be retrieved.
protoname
The pointer to the character string that contains the name of the protocol that further
qualifies the search criteria. For example, if port is 10, and the protoname is tcp, then call will
return the server that uses the TCP protocol on port number 10.
The structure struct servent is defined in <netdb>
struct servent
{
char *s_name; /* official service name */
char **s_aliases; /* alias list */
int s-port; /* port number, network-byte order */
char *s_proto; /* protocol to use */
};
s_name points to the character string that contains the name of the service.
s_aliases is a pointer to a NULL terminated array of alternate names for the service.
s_port is the port number assigned to the service
s_proto is the protocol being used by the service.
PART A
1. What is the use of getsockopt function?
The getsockopt function is used to get the values of socket options that were set already.
The prototype of getsockopt as follows.
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
sockfd must refer to an open socket descriptor.
level indicates whether the socket options is generic or protocol-specific.
optval is a pointer to a variable into which the current value of the option is stored by
getsockopt( ).
optlen is the size of optval.
2. What is the use of setsockopt function?
The setsockopt function is used to set the values for the socket options. The prototype of
setsockopt is as follows:
int setsockopt(int sockfd, int level, int optname, const void *optval socklen_t optlen);
sockfd must refer to an open socket descriptor.
level indicates whether the socket options is generic or protocol-specific.
optval is a pointer to a variable from which the new value of the option is fetched by
setsockopt.
optlen is the size of optval.
3. What is pending error?
When an error occurs on a socket, the kernel sets a variable named SO_ERROR to one of
standard values. This is called the pending error.
4. What are the three scenarios resulted from SO_KEEPALIVE socket option?
i. The peer responds with the expected ACK.
ii. The peer responds with an RST
iii. There is no response from the peer to the keepalive signal.
5. What is half open connection?
If the client host crashes, the server process will never know about it. The server will
continually wait for input that can never arrive. This is called a half open connection.
6. What is an application ACK?
An application level acknowledgement is used to know that the peer application has read
our data. It is guaranteed that when the read in the client returns, the server process has read
the data we sent.
7. State the difference between TCP and UDP.
TCP UDP
Connection oriented Connection less
Reliable Unreliable
Byte stream oriented Datagram oriented
15. How the two datagrams sent on the unconnected UDP socket?
i. Connect the socket
ii. Output the first datagram
iii. Unconnect the socket
iv. Connect the socket
v. Output the second datagram
vi. Unconnect the socket.
16. How the two datagrams sent on the connected UDP socket?
i. Connect the socket
ii. Output the first datagram
iii. Output the second datagram
17. List the steps involved in multiplexing TCP and UDP echo server using select.
i. Create listening TCP socket
ii. Create UDP socket
iii. Establish signal handler for SIGCHLD
iv. Call select
v. Handle arrival of datagram
18. What is Domain Name System?
The Domain Name System, or DNS, is used to map between host names and IP
addresses. A host name can either be a simple name, or a FQDN(Fully Qualified Domain
Name).
19. What is the use of gethostbyname function?
The gethostbyname is a resolver function used to map a host name into its IP address.
20. What is the use of gethostbyaddr function?
The gethostbyaddr is a resolver function used to map a IP address into a host name.
21. What is a name server?
A name server is a program called BIND (Berkeley Internet Name Domain) which
contains the mappings for names to numeric addresses.
22. What is the function of gethostbyname ( )? [Jun 2007]
Host computers are normally known by human readable names. Most applications should
deal with names not addresses.
The most basic function that look up a host name is gethostbyname( ).
If successful, it returns a pointer to a hostent structure that contains all the IPv4 addresses
for the host.
23. Write about IP Socket Options. [Dec 07]
In addition to binding a socket to a local address or connecting it to a destination address,
application programs need a method to control the socket. Such IP socket options are
IP_HDRINCL: If this option is set for a raw IP socket.
IP_OPTIONS: sets or get the IP options to be sent with every packet from this socket.
IP_TTL: set or retrieve the current time to live field that is sending in every packet send
from this socket.
PART B
1. Write a socket program to implement UDP echo client/ server application?
Fig: simple UDP echo client and server
Client-read the i/p from standard i/p and writes to the server, read line from the server
and prints it on its standard output.
Server-read the line from the network and echoes it to the client
UDP-echo server program
dg_echo fuction
UDP _Echo client program
dg_cli function
2. What is meant by generic socket option? Explain in detail.
Definition
Level_SOL_SOCKET
SO_BROADCAST, SO_DEBUG, SO_DONTROUTE, SO_ERROR,
SO_KEEPALIVE,SO_RCVBUF,SO_SNDBUF,SO_OOBLINE,SO_RCVLOWAT,
SO_SNDLOWAT,SO_RCVTIMEO,SO_SNDTIMEO,SO_REUSEADDR,SO_REU
SEPORT
3. IP socket option
IP socket options-level IPPROTO_IP
IP_HDRINCL
IP_OPTIONS
IP_RECVDSTADDR
IP_RECVIF
IP_TOS
IP_TTL
4. TCP socket options
TCP_KEEPALIVE
TCP_MAXRT
TCP_MAXSEG
TCP_NODELAY
TCP_STDURG
4. Write a program to display the port number from a given service name.
Syntax for getservbyname
Program using getservbyname
5. Write a program to find the IP address from a given host name?
Syntax for gethostbyname
Program using gethostbyname
6. Elementary UDP sockets.
Fig: UDP socket function
Description and syntax of various system calls
Socket(),bind(), recvfrom(), sendto(),close()
7. Domain Name system
DNS is used to map between hostname and IP addresses.
Components of DNS
Resolver, Name server, Database of resource records
Functions of Domain Name system
Fig:Resolver and Name servers
DNS alternatives
gethostbyname and gethostbyaddr function
struct hostent *gethostbyname(const char *hostname)
struct hostent *gethostbyaddr(const char *addr, socklen_t len, int family);
getservbyname and getservbyport function
struct servent *getservbyname(const char *servname,const char
*protoname)
struct servent *getservbyport(int port,const char *protoname)