UNIT II Application Development: TCP Echo Server
UNIT II Application Development: TCP Echo Server
TCP Echo Server – TCP Echo Client – Posix signal handling – Server with multiple clients
– boundary conditions : Server process Crashes, Server host Crashes, Server Crashes and
reboots, Server Shutdown – I/O multiplexing – I/O Models – select function – shutdown
function – TCP Echo server with multiplexing – poll function – TCP Echo client with
multiplexing.
1. TCP Echo Server
A simple echo server performs the following steps:
i. The client reads a line of text from its standard input and writes the line to the server.
ii. The server reads the line from its network input and echoes the line back to the client.
iii. The client reads the echoed line and prints it on its standard output.
A more efficient approach uses a “Connection manager” as the design centerpiece. The
idea is to provide a mechanism to store and retrieve client connection information. The server
application can simply retrieve client connections from the manager and service them in a loop.
Advantages of Multiple Clients / Single Server
More efficient division of process.
Horizontal and vertical scaling of resources.
Better price/ performance on client machines.
Ability to use familiar tools on clients machines
Client access to remote data ( via standards)
Full DBMS functionality provided to client workstations.
Overall better system price / performance.
Disadvantages with Multiple client / Single server
Server forms bottleneck
Server forms single point of failure
Database scaling difficult
The server still uses only one thread, but it can handle multiple clients simultaneously by
time multiplexing among them. Within the network listening loop it repeatedly polls the network
connections and when it determines that one is ready to send / receive data it checks whether it is
a new connection request or an already connected one; in the former case it accepts a new
connection with a new forthcoming client; in the later it sends or receive data as appropriate.
This scheme can create powerful services, because it takes advantages of the time delays
in the clients and in the network: a client may need to maintain a connection open for a long
time, but use it only for short busts. In between the server can select and serve or create other
connections. However the selection itself does not come for free, and it`s acceptable when CPU
use is not an issue, but presents a problem if the service requires high performance.
5. Boundary conditions
The following conditions are applicable for the server process.
i. Server process Crashes
ii. Server host Crashes
iii. Server Crashes and reboots
iv. Server Shutdown
Server process Crashes / Server process termination
After starting client/server, the server child process is killed. This simulates the crashing
of the server process, then what happens to client. The following steps take place:
1. We start the server and client on different hosts and type one line to the client to verify
that all is OK. That line is echoed normally by the server child.
2. Identify the process ID of the server child and kill it. As part of the process termination,
all open descriptors in the child are closed. This causes a FIN to be sent to the client, and
the client TCP responds with an ACK. This is the first half of the TCP connection
termination.
3. The SIGCHLD signal is sent to the server parent and handled correctly.
4. Nothing happens at the client. The client receives the FIN from the server TCP and
responds with an ACK, but the problem is that the client process is blocked in the call to
fgets waiting for a line from the terminal.
5. When we type "another line," str_cli calls writen and the client TCP sends the data to the
server. This is allowed by TCP because the receipt of the FIN by the client TCP only
indicates that the server process has closed its end of the connection and will not be
sending any more data. The receipt of the FIN does not tell the client that the server
process has terminated.
6. When the server TCP receives the data from the client, it responds with an RST since the
process that had that socket open has terminated. We can verify that the RST was sent by
watching the packets with tcpdump.
7. The client process will not see the RST because it calls readline immediately after the
call to writen and readline returns 0 (EOF) immediately because of the FIN that was
received in Step 2. Our client is not expecting to receive an EOF at this point so it quits
with the error message "server terminated prematurely."
8. When the client terminates (by calling err_quit), all its open descriptors are closed.
The problem in this example is that the client is blocked in the call to fgets when the FIN
arrives on the socket. The client is really working with two descriptors—the socket and the user
input—and instead of blocking on input from any one of the two sources, it should block on
input from either source. Indeed, this is one purpose of the select and poll functions
Server host Crashes
Next scenario is to see what happens when the server host crashes. To simulate this, we
must run the client and server on different hosts. We then start the server, start the client, type in
a line to the client to verify that the connection is up, disconnect the server host from the
network, and type in another line at the client. This also covers the scenario of the server host
being unreachable when the client sends data (i.e., some intermediate router goes down after the
connection has been established).
The following steps take place:
1. When the server host crashes, nothing is sent out on the existing network connections. That
is, we are assuming the host crashes and is not shut down by an operator.
2. We type a line of input to the client, it is written by writen, and is sent by the client TCP as
a data segment. The client then blocks in the call to readline, waiting for the echoed reply.
3. If we watch the network with tcpdump, we will see the client TCP continually
retransmitting the data segment, trying to receive an ACK from the server. When the client
TCP finally gives up, an error is returned to the client process. Since the client is blocked in
the call to readline, it returns an error. If the server host crashed and there were no
responses at all to the client's data segments, the error is ETIMEDOUT. If some
intermediate router determined that the server host was unreachable and responded with an
ICMP "destination unreachable' message, the error is either EHOSTUNREACH or
ENETUNREACH.
This scenario detects that the server host has crashed only when we send data to that host.
We need to use another technique, if we want to detect the crashing of the server host even if we
are not actively sending it data.
Server Crashes and reboots
In this scenario, we will establish a connection between the client and server and then
assume the server host crashes and reboots. The server host reboot before sending it data. The
easiest way to simulate this is to establish the connection, disconnect the server from the
network, shut down the server host and then reboot it, and then reconnect the server host to the
network.
If the client is not actively sending data to the server when the server host crashes, the
client is not aware that the server host has crashed. The following steps take place:
1. We start the server and then the client. We type a line to verify that the connection is
established.
2. The server host crashes and reboots.
3. We type a line of input to the client, which is sent as a TCP data segment to the server
host.
4. When the server host reboots after crashing, its TCP loses all information about
connections that existed before the crash. Therefore, the server TCP responds to the
received data segment from the client with an RST.
5. Our client is blocked in the call to readline when the RST is received, causing readline to
return the error ECONNRESET.
If it is important for our client to detect the crashing of the server host, even if the client is not
actively sending data, then this technique cannot be used.
Server Shutdown
When a Unix system is shut down, the init process normally sends the SIGTERM signal
to all processes, waits some fixed amount of time (often between 5 and 20 seconds), and then
sends the SIGKILL signal to any processes still running. This gives all running processes a short
amount of time to clean up and terminate. If we do not catch SIGTERM and terminate, our
server will be terminated by the SIGKILL signal. When the process terminates, all open
descriptors are closed. We must use the select or poll function in our client to have the client
detect the termination of the server process as soon as it occurs.
6. I/O multiplexing
When an application needs to handle multiple I/O descriptors at the same time then I/O
multiplexing is used.
I/O multiplexing is the capability of kernel to notify that one or more I/O conditions are
ready.
I/O multiplexing is provided by select & poll functions.
I/O multiplexing is used in the following networking applications.
It is possible, for a client to handle multiple descriptors I/O multiplexing should be used.
It is possible, but rare, for a client to handle multiple sockets at the same time.
If a TCP server handles both a listening socket and its connected sockets, I/O
multiplexing is normally used.
If a server handles TCP and UDP, I/O multiplexing is normally used.
If a server handles multiple services and multiple protocol then I/O multiplexing is
normally used.
select function
Select function allows the process to instruct the kernel to wait for any one of multiple events
to occur and to wake up the process only when one or more of these events occurs or when a
specified amount of time has passed.
The events are
Descriptors any one of the set that are ready for reading
Descriptors any one of the set that are ready for writing
Exceptions arrived on any of the description set.
Syntax of select ( )
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const
struct timeval *timeout);
Returns: positive count of ready descriptors that are ready to read or write or handle
exceptions. 0 on timeout, –1 on error
We start our description of this function with its final argument, which tells the kernel how
long to wait for one of the specified descriptors to become ready.
A timeval structure specifies the number of seconds and microseconds.
struct timeval
{
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
There are three possibilities:
1. Wait forever
Return only when one of the specified descriptors is ready for I/O.
The timeout argument is set as a null pointer.
2. Wait up to a fixed amount of time
timeout is set with specified time in seconds or milliseconds.
Return only when one of the specified descriptors is ready for I/O, but do not wait
beyond the number of seconds and microseconds specified in the timeval
structure pointed to by the timeout argument.
3. Do not wait at all
Return immediately after checking the descriptors. This is called polling.
The timer value must be 0.
In the syntax of select ( ) function, maxfdp1 specifies the number of descriptors to be tested.
The three middle arguments, readset, writeset, and exceptset, specify the descriptors that
we want to test for reading, writing, and exception conditions.
There are only two exception conditions currently supported:
1. The arrival of out-of-band data for a socket.
2. The presence of control status information.
The argument of select ( ) readset, writeset and exceptset pointers are value result arguments.
When we call the select ( ), we specify the values of descriptors that we are interested in and
on return the result indicates which descriptors are ready.
Descriptor Is Ready under the following Conditions
A socket is ready for reading if any of the following four conditions is true:
The number of bytes of data in the socket receive buffer is greater than or equal to the
current size of the low-water mark for the socket receive buffer. A read operation on
the socket will not block and will return a value greater than 0 (i.e., the data that is
ready to be read).
The read half of the connection is closed i.e., a TCP connection that has received a FIN.
The socket is a listening socket and the number of completed connections is nonzero.
A socket error is pending. A read operation on the socket will not block and will return
an error (–1). These pending errors can also be fetched and cleared by getsockopt.
A socket is ready for writing if any of the following four conditions is true:
The number of bytes of available space in the socket send buffer is greater than or equal
to the current size of the low-water mark for the socket send buffer.
The purpose of receive and send low water marks is to represent how much data
must be available for reading or how much space must be available for writing.
The write half of the connection is closed.
A socket using a non-blocking connect has completed the connection, or the connect
has failed.
A socket error is pending. A write operation on the socket will not block and will return
an error (–1). These pending errors can also be fetched and cleared by getsockopt.
A socket has an exception condition pending if there is out-of-band data for the socket.
shutdown function
The normal way to terminate a network connection is to call the close function.
But close functions has two limitations
1. close decrements the descriptor's reference count and closes the socket only if the count
reaches 0. With shutdown, we can initiate TCP's normal connection termination sequence
(the four segments beginning with a FIN), regardless of the reference count.
2. close terminates both directions of data transfer, reading and writing. Since a TCP
connection is full-duplex, there are times when we want to tell the other end that we have
finished sending, even though that end might have more data to send. This situation is
represented in the following fig:
Fig. Calling shutdown to close half of a TCP connection.
Syntax
#include <sys/socket.h>
int shutdown(int sockfd, int howto);
Returns: 0 if OK, –1 on error
The action of the function depends on the value of the howto argument.
sockfd specifies file descriptor of the socket.
howto specifies the type of shut down. The values are
SHUT_RD
Disables further read operation.
The read half of the connection is close.
No more data is received and any data currently in the socket receive buffer is discarded.
The process can no longer issue any of the read functions on the socket. Any data
received after this call for a TCP socket is acknowledged and then silently discarded.
SHUT_WR
The write half of the connection is closed
Any data currently in the socket send buffer will be sent, followed by TCP's normal
connection termination sequence.
SHUT_RDWR
Both read half and the write half of the connections are closed.
This is equivalent to calling shutdown twice: first with SHUT_RD and then with
SHUT_WR.
poll function
The poll function originated with SVR3 and was originally limited to STREAMS devices.
poll provides functionality that is similar to select, but poll provides additional information
when dealing with STREAMS devices.
Syntax
#include <poll.h>
int poll (struct pollfd *fdarray, unsigned long nfds, int timeout);
Returns: count of ready descriptors, 0 on timeout, –1 on error
The first argument is a pointer to the first element of an array of structures. Each element of
the array is a pollfd structure that specifies the conditions to be tested for a given descriptor,
fd.
struct pollfd
{
int fd; /* descriptor to check */
short events; /* events of interest on fd */
short revents; /* events that occurred on fd */
};
The conditions to be tested are specified by the events member, and the function returns the
status for that descriptor in the corresponding revents member. (Having two variables per
descriptor, one a value and one a result, avoids value-result arguments.)
nfds argument specifies the number of elements in the fdarray of structure.
fdarray -> pointer to an array of structures pollfd, each member of the array.
The timeout argument specifies how long the function is to wait before returning. A positive
value specifies the number of milliseconds to wait.
Return values of poll ( ) function
Upon successful completion, poll ( ) shall return a non – negative value.
A positive value indicates the total number of file descriptors that have been selected.
A value of 0 indicates that the call timeout and no file descriptors have been selected.
Upon failure poll ( ) returns -1 and set errno to indicate the error.
There are 3 classes of data identified by poll. They are Normal, Priority band and high
priority. The following table shows the constants used to specify the events flag and to test the
revents flag against.
We have divided this table into three sections: The first four constants deal with input, the
next three deal with output, and the final three deal with errors. Notice that the final three cannot
be set in events, but are always returned in revents when the corresponding condition exists.
With regard to TCP and UDP sockets, the following conditions cause poll to return the
specified revent.
All regular TCP data and all UDP data are considered normal.
TCP's out-of-band data is considered priority band.
When the read half of a TCP connection is closed, this is also considered normal data and a
subsequent read operation will return 0.
The presence of an error for a TCP connection can be considered either normal data or an
error (POLLERR).
The availability of a new connection on a listening socket can be considered either normal
data or priority data.
7. I/O Models
There are five I /O models in the Unix. These are:
a. Blocking I /O
b. Non blocking I / O
c. I/O Multiplexing (select and poll)
d. Signal driven I/O (SIGIO)
e. Asynchronous I/O (the Posix 1 aio_functions)
There are two distinct phases for an input operation.
*waiting for the data to be read - waiting for the data to arrive on the network.
When the packet arrives, it is copied into buffer within the kernel.
*Copying the data from the kernel to the process- copying this data from the
kernel’s buffer into our applications buffer.
Blocking I/O Model:
By default, all sockets are blocking.
For explaining the scenario UDP socket is used.
The process calls recvfrom and the system call does not return until the datagram arrives and is
copied into our application buffer, or an error occurs.
The process is blocked the entire time from when it calls recvfrom until it returns.
When recvfrom returns OK, our application processes the datagram.
When the socket is set to non blocking I/O, the kernel is told that “when I/O operation that I
request cannot be completed without putting the process to sleep, do not put the process to
sleep but return an error message instead.”
During the first three times, when the recvfrom is called, there is no data to return, so the
kernel immediately returns an error EWOULDBLOCK.
Fourth time, when recvfrom is called, the datagram is ready, it is copied into our application
buffer and the recvfrom returns OK. The application then process the data.
When an application calls recvfrom function repeatedly until the data is ready, it is called
polling.
The continuation polling of the kernel is waste of CPU time. But this model is normally
encountered on system that are dedicated to one function.
I / O Multiplexing Model :
In this model select or poll functions are called instead of recvfrom.
The select function allows the process to instruct the kernel to wait for any one of the
multiple events to occur and it wake up the process for an event occur.
The call to select is blocked waiting for the datagram socket to be readable. When select
returns that the socket is readable, then the recvfrom is called to copy the datagram into the
application buffer.
Compared to blocking model, the difference here is that the application can wait for more
than one descriptors to be ready. The disadvantages is that select requires two system calls.
To see if there is data to be read, if data can be written or an exception condition is present.
select ( ) system call allow us to use blocking I/O on a set of descriptors. (file, skt)
Eg: We can ask select to notify us when data is available for reading an either STDIN OR
TCP socket.
read), file offset (similar to lseek), and how to notify us when the entire operation is
complete.
This system call returns immediately and our process is not blocked while waiting for the
I/O to complete.
It is expected that the kernel will generate some signal when the operation is complete.
This signal is generated only when the data is copied completely in the application buffer.
Comparison of the I/O Models
The following table shows the comparison of the five different I/O models. It shows that
the main difference between the first four models is the first phase, as the second phase in the
first four models is the same: the process is blocked in a call to recvfrom while the data is copied
from the kernel to the caller's buffer. Asynchronous I/O, however, handles both phases and is
different from the first four.
Synchronous I/O versus Asynchronous I/O
A synchronous I/O operation causes the requesting process to be blocked until that I/O
operation completes.
An asynchronous I/O operation does not cause the requesting process to be blocked.
Based on this definitions, the first four I/O models—blocking, nonblocking, I/O multiplexing,
and signal-driven I/O—are synchronous because the actual I/O operation (recvfrom) blocks the
process. Only the asynchronous I/O model matches the asynchronous I/O definition.
8. TCP Echo server with multiplexing
TCP echo server with multiplexing involves a single process that uses select to handle any
number of clients, instead of forking one child per client.
Data structures are used to keep track of the clients.
Fig. shows the state of the server before the first client has established a connection.
The server has a single listening descriptor. The server maintains only a read descriptor set.
Assume that the server is started in the foreground, so descriptors 0, 1, and 2 are set to
standard input, output, and error.
Therefore, the first available descriptor for the listening socket is 3.
Array of integers named client that contains the connected socket descriptor for each client.
All elements in this array are initialized to –1.
Figure: Data structures for TCP server with just a listening socket.
The only nonzero entry in the descriptor set is the entry for the listening sockets and the
first argument to select will be 4.
When the first client establishes a connection with our server, the listening descriptor
becomes readable and our server calls accept.
The new connected descriptor returned by accept will be 4. Figure shows the connection
from the client to the server.
Figure: TCP server after first client establishes connection.
The new connected socket (which we assume is 5). So the data structures will be
Figure: Data structures after second client connection is established.
We assume the first client terminates its connection. The client TCP sends a FIN, which
makes descriptor 4 in the server readable. When our server reads this connected socket,
read returns 0.
We then close this socket and update our data structures accordingly. The value of client
[0] is set to –1 and descriptor 4 in the descriptor set is set to 0. But the value of maxfd does
not change.
Figure: Data structures after first client terminates its connection.
As clients arrive, we record their connected socket descriptor in the first available entry in
the client array.
We must also add the connected socket to the read descriptor set.
The variable maxi is the highest index in the client array that is currently in use and the
variable maxfd (plus one) is the current value of the first argument to select.
The only limit on the number of clients that this server can handle is the minimum of the
two values FD_SETSIZE and the maximum number of descriptors allowed for this process
by the kernel.
Program for TCP server using a single process & select.
#include "unp.h"
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
fd_set rset, allset;
char buf[MAXLINE];
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
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);
Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
maxfd = listenfd; /* initialize */
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
This coding are the first half of the server. These steps are used to create the socket,
bind & listen the sockets and initialize the data structures array into -1.
for ( ; ; )
{
rset = allset; /* structure assignment */
nready = Select(maxfd + 1, &rset, NULL, NULL, NULL);
if (FD_ISSET(listenfd, &rset))
{ /* new client connection */
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0)
{
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE)
err_quit("too many clients");
FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd)
maxfd = connfd; /* for select */
if (i > maxi)
maxi = i; /* max index in client[] array */
if (--nready <= 0)
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++)
{ /* check all clients for data */
if ( (sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset))
{
if ( (n = Read(sockfd, buf, MAXLINE)) == 0))
{ /* connection closed by client */
Close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
}
else
Writen(sockfd, buf, n);
if (--nready <= 0)
break; /* no more readable descriptors */
}
}
}
}
After initializing the data structures, select function is used. select waits for either the
establishment of a new client connection or the arrival of data, a FIN, or an RST on an
existing connection.
If the listening socket is readable, a new connection has been established.
Call accept and update our data structures accordingly.
We use the first unused entry in the client array to record the connected socket.
The number of ready descriptors is decremented, and if it is 0, we can avoid the next for
loop.
For checking the existing client connection.
By using a readline ( ) function a line is read from the client and echoed back to the client.
If the client closes the connection, read returns 0 and we update our data structures
accordingly.
Denial-of-Service Attacks
When a server is handling multiple clients, the server can never block in a function call
related to a single client. Otherwise the server deny the service to all other clients. This is called
a denial-of-service attack.
10. TCP Echo client with multiplexing.
In ordinary TCP Echo client, the problem is that the process could be blocked in the call
to fgets when something happened on the socket.
But In TCP Echo client with multiplexing, instead of blocking a call to select wait for
standard input or the socket to be readable will block a call to socket.
Three conditions are handled with the socket:
i. If the server TCP sends data, the socket becomes readable and read returns greater than 0
(number of bytes of data).
ii. If the server TCP sends FIN (process terminates) the select becomes readable and read
returns 0.
iii. If the server TCP sends RST (server host crashes and reboots) the socket become
readable, read returns -1.
Source code of strcli function that uses select is
#include "unp.h"
void str_cli(FILE *fp, int sockfd)
{
int maxfdp1;
fd_set rset;
char sendline[MAXLINE], recvline[MAXLINE];
// call select
FD_ZERO(&rset);
for ( ; ; )
{
FD_SET(fileno(fp), &rset);
FD_SET(sockfd, &rset);
maxfdp1 = max(fileno(fp), sockfd) + 1;
Select(maxfdp1, &rset, NULL, NULL, NULL);
// handle readable socket
if (FD_ISSET(sockfd, &rset))
{
if (readline(sockfd,recvline, MAXLINE)) == 0)
err_quit("str_cli: server terminated prematurely");
}
if (FD_ISSET(fileno(fp), &rset))
{ /* input is readable */
if (fgets(sendline,MAXLINE, fp) == 0)
return;
Writen(sockfd, sendline, strlen(sendline));
}
}
}
PART A
1. List the steps involved in creating a TCP echo server.
i. Create a socket
ii. Bind server’s well known port
iii. Wait for client connection to complete
iv. Read a line
v. Echo the line to client
2. List the steps involved in creating a TCP echo client.
i. Create a socket; fill in internet socket address structure
ii. Connect to server
iii. Read a line from standard input and write it to server.
iv. Read echoed line from server and write it to standard output.
3. What is signal?
A signal is a notification to a process that an event has occurred. They are also called
software interrupts.
4. What are the medium of communications of the signal?
Signal can be sent
By one process to another process
By the kernel to a process.
5. What is the use of SIGCHILD signal?
The SIGCHILD signal is sent by the kernel whenever a process terminates, to the parent
of the terminating process.
6. What is the use of a ‘sigaction’ function?
The sigaction function allows the calling process to examine and/or specify the action to be
associated with a specific signal.
7. What is a disposition?
Disposition is action, set using sigaction function, associated with signal.
8. What are the three choices of disposition?
The three choices of disposition are:
i. Default handler: We can set the default disposition by setting its disposition to
SIG_DFL.
ii. User defined signal handler: We can provide a function that is called whenever
a specific signal occurs.
iii. Ignoring the signal: We can ignore a signal by setting its disposition to
SIG_IGN.
9. Which two signals cannot be ignored and cannot be caught?
SIGCHILD
SIGURG
10. What is a Zombie process?
A zombie is one that has completed its execution but still has an entry in the process
table, allowing the process that started it to read its exit status.
11. What is the difference between wait and waitpid functions?
wait – If a process calls wait ( ) and if it has one or more children that are executing, then
wait blocks until the first of the existing children terminate.
waitpid – waitpid gives us more control over which process to wait for. The pid argument
specifies the process ID that is to wait for.
12. What is the use of WNOHANG option?
This tells the kernel not to block if there are no terminated children; it blocks only if there
are children still executing.
13. What is the use of SIGPIPE signal?
When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to
the process. The default action of this signal is to terminate the process so the process must
catch the signal to avoid being involuntarily terminated.
14. Which functions are used to provide I/O multiplexing?
The select function and poll function.
15. What is I/O multiplexing?
I/O multiplexing is the capability to tell the kernel that we want to be notified if one or
more I/O conditions are ready. If input is ready to be read or the descriptor is capable of
taking more output.
16. List the uses of I/O multiplexing in networking applications.
I/O multiplexing is used in networking applications in the following sceneries:
A client handling multiple descriptors.
A client handling multiple sockets at the same time.
A TCP server handling both a listening socket and its connected sockets.
A server handling TCP and UDP.
A server handling multiple services and perhaps multiple protocols.
17. Mention any five I/O models. [ Dec 07]
i. Blocking I/O
ii. Nonblocking I/O
iii. I/O multiplexing
iv. Signal driven I/o
v. Asynchronous I/O
18. State where POSIX signal handling is used. [Dec 07]
A signal is a software interrupt delivered to a process.
The operating system uses POSIX signals to report exceptional situations to an
executing program.
Some POSIX signals report errors such as references to invalid memory addresses.
Others report asynchronous events, such as disconnection.
The termination of a child process.
Expiration of a timer or alarm.
A call to kill or rains by the same process.
19. Write about poll function. [June 07]
The poll ( ) function provides applications with a mechanism for multiplexing input /
output over a set of file descriptors. The poll ( ) function shall identify those file descriptors
on which an application can read or write data, or on which certain events have occurred.
20. Write the syntax for select function. [June 07]
The select system call can be used with socket to provide a synchronous multiplexing
mechanism.
#include < sys/select.h>
#include < sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const
struct timeval *timeout);
21. Explain the syntax of the signal function. [ May 08]
#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
The signal function chooses one of three ways in which receipt of the signal number sig
is to be subsequently handled. If the value of func is SIG_DFL, default handling for that
signal shall occur. If the value of func is SIG_IGN, the signal shall be ignored. Otherwise,
the application shall ensure that func points to a function to be called when that signal occurs.
An invocation of such a function because of a signal, or of any further functions called by
that invocation is called a “signal handler”.
22. What is the difference between close ( ) system call and shutdown ( ) system call?[Apr10]
Close ( ) Shutdown( )
Connection termination is initiated only if We can initiate connection termination
reference count reaches 0. without the reference count.
It is only possible to terminate the It is possible to terminate the connections in
connections on both sides of data transfer. three ways.
Reading side
Writing side
Both sides