Relocated example program and made its .SH title "EXAMPLE".

This commit is contained in:
Michael Kerrisk 2007-05-16 02:01:52 +00:00
parent 0784f93ce4
commit 3618596929
1 changed files with 156 additions and 156 deletions

View File

@ -342,7 +342,162 @@ A simple example of the use of
can be found in the
.BR select (2)
manual page.
.SH PORT FORWARDING EXAMPLE
.SS Select Law
Many people who try to use
.BR select ()
come across behavior that is
difficult to understand and produces non-portable or borderline
results.
For instance, the above program is carefully written not to
block at any point, even though it does not set its file descriptors to
non-blocking mode at all (see
.BR ioctl (2)).
It is easy to introduce
subtle errors that will remove the advantage of using
.BR select (),
hence I will present a list of essentials to watch for when using the
.BR select ()
call.
.TP
\fB1.\fP
You should always try to use
.BR select ()
without a timeout.
Your program
should have nothing to do if there is no data available.
Code that
depends on timeouts is not usually portable and is difficult to debug.
.TP
\fB2.\fP
The value \fInfds\fP must be properly calculated for efficiency as
explained above.
.TP
\fB3.\fP
No file descriptor must be added to any set if you do not intend
to check its result after the
.BR select ()
call, and respond
appropriately.
See next rule.
.TP
\fB4.\fP
After
.BR select ()
returns, all file descriptors in all sets
should be checked to see if they are ready.
.\" mtk, May 2006: the following isn't really true.
.\" Any file descriptor that is available
.\" for writing \fImust\fP be written to, and any file descriptor
.\" available for reading \fImust\fP be read, etc.
.TP
\fB5.\fP
The functions
.BR read (2),
.BR recv (2),
.BR write (2),
and
.BR send (2)
do \fInot\fP necessarily read/write the full amount of data
that you have requested.
If they do read/write the full amount, its
because you have a low traffic load and a fast stream.
This is not
always going to be the case.
You should cope with the case of your
functions only managing to send or receive a single byte.
.TP
\fB6.\fP
Never read/write only in single bytes at a time unless your are really
sure that you have a small amount of data to process.
It is extremely
inefficient not to read/write as much data as you can buffer each time.
The buffers in the example above are 1024 bytes although they could
easily be made larger.
.TP
\fB7.\fP
The functions
.BR read (2),
.BR recv (2),
.BR write (2),
and
.BR send (2)
as well as the
.BR select ()
call can return \-1 with
.I errno
set to \fBEINTR\fP,
or with
.I errno
set to \fBEAGAIN\fP (\fBEWOULDBLOCK\fP).
These results must be properly managed (not done properly
above).
If your program is not going to receive any signals then
it is unlikely you will get \fBEINTR\fP.
If your program does not
set non-blocking I/O, you will not get \fBEAGAIN\fP.
Nonetheless
you should still cope with these errors for completeness.
.TP
\fB8.\fP
Never call
.BR read (2),
.BR recv (2),
.BR write (2),
or
.BR send (2)
with a buffer length of zero.
.TP
\fB9.\fP
If the functions
.BR read (2),
.BR recv (2),
.BR write (2),
and
.BR send (2)
fail
with errors other than those listed in \fB7.\fP,
or one of the input functions returns 0, indicating end of file,
then you should \fInot\fP pass that descriptor to
.BR select ()
again.
In the above example,
I close the descriptor immediately, and then set it to \-1
to prevent it being included in a set.
.TP
\fB10.\fP
The timeout value must be initialized with each new call to
.BR select (),
since some operating systems modify the structure.
.BR pselect ()
however does not modify its timeout structure.
.TP
\fB11.\fP
I have heard that the Windows socket layer does not cope with OOB data
properly.
It also does not cope with
.BR select ()
calls when no file
descriptors are set at all.
Having no file descriptors set is a useful
way to sleep the process with sub-second precision by using the timeout.
(See further on.)
.SS Usleep Emulation
On systems that do not have a
.BR usleep (3)
function, you can call
.BR select ()
with a finite timeout and no file descriptors as
follows:
.PP
.nf
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000; /* 0.2 seconds */
select(0, NULL, NULL, NULL, &tv);
.fi
.PP
This is only guaranteed to work on Unix systems, however.
.SH EXAMPLE
Here is an example that better demonstrates the true utility of
.BR select ().
The listing below is a TCP forwarding program that forwards
@ -633,161 +788,6 @@ time, although it could easily be extended to do this with a linked list
of buffers \(em one for each connection.
At the moment, new
connections cause the current connection to be dropped.
.SS Select Law
Many people who try to use
.BR select ()
come across behavior that is
difficult to understand and produces non-portable or borderline
results.
For instance, the above program is carefully written not to
block at any point, even though it does not set its file descriptors to
non-blocking mode at all (see
.BR ioctl (2)).
It is easy to introduce
subtle errors that will remove the advantage of using
.BR select (),
hence I will present a list of essentials to watch for when using the
.BR select ()
call.
.TP
\fB1.\fP
You should always try to use
.BR select ()
without a timeout.
Your program
should have nothing to do if there is no data available.
Code that
depends on timeouts is not usually portable and is difficult to debug.
.TP
\fB2.\fP
The value \fInfds\fP must be properly calculated for efficiency as
explained above.
.TP
\fB3.\fP
No file descriptor must be added to any set if you do not intend
to check its result after the
.BR select ()
call, and respond
appropriately.
See next rule.
.TP
\fB4.\fP
After
.BR select ()
returns, all file descriptors in all sets
should be checked to see if they are ready.
.\" mtk, May 2006: the following isn't really true.
.\" Any file descriptor that is available
.\" for writing \fImust\fP be written to, and any file descriptor
.\" available for reading \fImust\fP be read, etc.
.TP
\fB5.\fP
The functions
.BR read (2),
.BR recv (2),
.BR write (2),
and
.BR send (2)
do \fInot\fP necessarily read/write the full amount of data
that you have requested.
If they do read/write the full amount, its
because you have a low traffic load and a fast stream.
This is not
always going to be the case.
You should cope with the case of your
functions only managing to send or receive a single byte.
.TP
\fB6.\fP
Never read/write only in single bytes at a time unless your are really
sure that you have a small amount of data to process.
It is extremely
inefficient not to read/write as much data as you can buffer each time.
The buffers in the example above are 1024 bytes although they could
easily be made larger.
.TP
\fB7.\fP
The functions
.BR read (2),
.BR recv (2),
.BR write (2),
and
.BR send (2)
as well as the
.BR select ()
call can return \-1 with
.I errno
set to \fBEINTR\fP,
or with
.I errno
set to \fBEAGAIN\fP (\fBEWOULDBLOCK\fP).
These results must be properly managed (not done properly
above).
If your program is not going to receive any signals then
it is unlikely you will get \fBEINTR\fP.
If your program does not
set non-blocking I/O, you will not get \fBEAGAIN\fP.
Nonetheless
you should still cope with these errors for completeness.
.TP
\fB8.\fP
Never call
.BR read (2),
.BR recv (2),
.BR write (2),
or
.BR send (2)
with a buffer length of zero.
.TP
\fB9.\fP
If the functions
.BR read (2),
.BR recv (2),
.BR write (2),
and
.BR send (2)
fail
with errors other than those listed in \fB7.\fP,
or one of the input functions returns 0, indicating end of file,
then you should \fInot\fP pass that descriptor to
.BR select ()
again.
In the above example,
I close the descriptor immediately, and then set it to \-1
to prevent it being included in a set.
.TP
\fB10.\fP
The timeout value must be initialized with each new call to
.BR select (),
since some operating systems modify the structure.
.BR pselect ()
however does not modify its timeout structure.
.TP
\fB11.\fP
I have heard that the Windows socket layer does not cope with OOB data
properly.
It also does not cope with
.BR select ()
calls when no file
descriptors are set at all.
Having no file descriptors set is a useful
way to sleep the process with sub-second precision by using the timeout.
(See further on.)
.SS Usleep Emulation
On systems that do not have a
.BR usleep (3)
function, you can call
.BR select ()
with a finite timeout and no file descriptors as
follows:
.PP
.nf
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000; /* 0.2 seconds */
select(0, NULL, NULL, NULL, &tv);
.fi
.PP
This is only guaranteed to work on Unix systems, however.
.SH RETURN VALUE
On success,
.BR select ()