Setting the SO_LINGER
Option
Another commonly
applied socket option is the SO_LINGER option. This option differs from the SO_REUSEADDR
option in that the data structure used
is not a simple int data type. The purpose of the SO_LINGER option is to
control how the socket is shut down when the function close(2) is called. This
option applies only to connection-oriented protocols such as TCP.
The default
behavior of the kernel is to allow the close(2) function to return immediately
to the caller. Any unsent TCP/IP data will be transmitted and delivered if
possible, but no guarantee is made. Because the close(2) call returns control
immediately to the caller, the application has no way of knowing whether the
last bit of data was actually delivered.
The SO_LINGER option
can be enabled on the socket, to cause the application to block in the close(2)
call until all final data is delivered to the remote end. Furthermore, this
assures the
caller that both
ends have acknowledged a normal socket shutdown. Failing this, the indicated option
timeout occurs and an error is returned to the calling application.
One final
scenario can be applied, by use of different SO_LINGER option values. If the
calling application wants to abort communications immediately, appropriate
values can be set in the
linger structure.
Then, a call to close(2) will initiate an abort of the communication link, discarding
all pending data and immediately close the socket.
The modes of
operation for SO_LINGER are controlled by the structure linger:
struct linger {
int l_onoff;
int l_linger;
};
The member l_onoff
acts as a Boolean value, where a nonzero value indicates TRUE and zero indicates
FALSE. The three variations of this option are specified as follows:
- Setting l_onoff to FALSE causes member l_linger to be ignored and the default close (2) behavior implied. That is, the close(2) call will return immediately to the caller, and any pending data will be delivered if possible.
- Setting l_onoff to TRUE causes the value of member l_linger to be significant. When l_linger is nonzero, this represents the time in seconds for the timeout period to be applied at close(2) time (the close(2) call will "linger"). If the pending data and successful close occur before the timeout occurs, a successful return takes place. Otherwise, an error return occur and errno is set to the value of EWOULDBLOCK.
- Setting l_onoff to TRUE and setting l_linger to zero causes the connection to be aborted and any pending data is immediately discarded upon close(2).
You are probably
well advised to write your applications so that the option SO_LINGER is enabled
and a reasonable timeout is provided. Then, the return value from close(2) can
be tested to see whether the
connection was mutually shut down successfully. If an error is returned
instead, this tells your application that it is probable that the remote
application was unable to receive all the data that you sent. Alternatively, it
might just mean that problems occurred when the connection was closed (after
the data was successfully received by the peer).
You must be
aware, however, that lingering in some server designs will create new problems.
When the SO_LINGER option is configured to linger upon close(2), this will
prevent other clients from being serviced while your server execution lingers
within the close(2) function call. This problem exists if you are serving many
clients within one process (usually a server that uses select(2) or poll(2)).
Using the default behavior might be more appropriate because it will allow close(2)
to return immediately. Any pending written data will still be delivered by the kernel,
if it is able to.
Finally, using
the abort behavior (mode number 3 listed previously) is appropriate if the
application or server knows that the connection should be aborted. This might
be applied when the server has determined that someone without access privilege
is attempting to gain access. The client in this situation deserves no special
care and so minimum overhead is expended in dispensing of the culprit.
The following
shows an example of enabling the linger option, using a timeout (linger value)
of 30 seconds:
Example
#define TRUE 1
#define FALSE 0
int z; /* Status
code */
int s; /* Socket
s */
struct linger
so_linger;
. . .
so_linger.l_onoff
= TRUE;
so_linger.l_linger
= 30;
z = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
if ( z ) {
perror("setsockopt(2)");
}
The next example
shows how to establish SO_LINGER values to effect an abort of the current connection
on socket s:
Example
#define TRUE 1
#define FALSE 0
int z; /* Status
code */
int s; /* Socket
s */
struct linger
so_linger;
. . .
so_linger.l_onoff
= TRUE;
so_linger.l_linger
= 0;
z = setsockopt(s,
SOL_SOCKET,
SO_LINGER,
&so_linger,
sizeof so_linger);
if ( z ) {
perror("setsockopt(2)");
}
close(s); /*
Abort connection */
In the prior
example, the socket connection s is aborted when the function close(2) is
called. The abort semantic is implied by setting the timeout value to zero
seconds.
See Also
SO_PASSCRED & SO_PEERCRED, SO_BROADCAST, SO_KEEPALIVE, SO_REUSEADD, SO_OBINLINE, SO_TYPE.
No comments:
Post a Comment