Unix Socket Programming (Contd..)
Multiple Sockets
Suppose
we have a process which has to handle multiple sockets. We cannot
simply read from one of them if a request comes, because that will
block while waiting on the request on that particular socket. In the
meantime a request may come on any other socket. To handle this
input/output multiplexing we could use different techniques :
- Busy waiting: In
this methodology we make all the operations on sockets non-blocking
and handle them simultaneously by doing polling. For example, we could
use the read() system call this way and read from all the sockets
together. The disadvantage in this is that we waste a lot of CPU
cycles. To make the system calls non-blocking we use: fcntl (s,
f_setfl, fndelay);
- Asynchronous I/O: Here we ask the Operating System to tell
us whenever we are waiting for I/O on some sockets. The Operating
System sends a signal whenever there is some I/O. When we receive a
signal, we will have to check all sockets and then wait till the next
signal comes. But there are two problems - first, the signals are
expensive to catch and second, we would not be able to know if an input
comes on a socket when we are doing I/O on another one. For
Asynchronous I/O, we have a different set of commands (here we give the
ones for UNIX with a VHD variant): signal(sigio, io_handler);
fcntl(s, f_setown, getpid()); fcntl(s, f_setfl, fasync);
- Separate process for each I/O: We could as well fork out 10
different child processes for 10 different sockets. These child
processes are very light weight and have some communication between
them. Now these processes waiting on each socket can have blocking
system calls. This wastes a lot of memory, data structures and other
resources.
- Select() system call: We can use the select system call to
instruct the Operating System to wait for any one of multiple events to
occur and to wake up the process only if one of these events occur.
This way we would know that the I/O request has come from which socket.
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set
*errorfds, struct timeval *timeout); void FD_CLR(int fd, fd_set
*fdset); int FD_ISSET(int fd, fd_set *fdset); void FD_SET(int fd,
fd_set *fdset); void FD_ZERO(fd_set *fdset);
The select() function indicates which of the specified file
descriptors is ready for reading, ready for writing, or has an error
condition pending. If the specified condition is false for all of the
specified file descriptors, select() blocks up to the specified
timeout interval, until the specified condition is true for at least one
of the specified file descriptors. The nfds argument specifies the
range of file descriptors to be tested. The select() function tests file descriptors in the range of 0 to nfds-1. readfds, writefds and errorfds arguments point to an object of type fd_set. readfds specifies the file descriptors to be checked for being ready to read. writefds specifies the file descriptors to be checked for being ready to write, errorfds specifies the file descriptors to be checked for error conditions pending.
On successful completion, the objects pointed to by the readfds, writefds, and errorfds
arguments are modified to indicate which file descriptors are ready
for reading, ready for writing, or have an error condition pending,
respectively. For each file descriptor less than nfds, the corresponding
bit will be set on successful completion if it was set on input and
the associated condition is true for that file descriptor. The timeout
is an upper bound on the amount of time elapsed before select returns.
It may be zero, causing select to return immediately. If the timeout
is a null pointer, select() blocks until an event causes one of
the masks to be returned with a valid (non-zero) value. If the time
limit expires before any event occurs that would cause one of the masks
to be set to a non-zero value, select() completes successfully and returns 0.
Reserved Ports
Port numbers from 1-1023 are reserved for
the superuser and the rest of the ports starting from 1024 are for
other users. But we have a finer division also which is as follows :
- 1 to 511 - these are assigned to the processes run by the superuser
- 512 to 1023 - they are used when we want to assign ports to some
important user or process but want to show that this is a reserved
superuser port
- 1024 to 5000 - they are system assigned random ports
- 5000 to FFFF - they are used to assign a port to user processes or sockets used by users
0 comments:
Post a Comment