The paragraphs which follow will describe operations incident to shutting down an established socket connection.
A socket connection can be taken down in one of several ways. WSPShutdown (with how equal to SD_SEND or SD_BOTH), and WSPSendDisconnect may be used to initiate a graceful connection shutdown. WSPCloseSocket can be used to initiate either a graceful or an abortive shutdown depending on the linger options as a side effect of closing a socket. See below for more information about graceful and abortive shutdown, and linger options.
Service providers indicate connection teardown that is initiated by the remote party via the FD_CLOSE network event. Graceful shutdown is also be indicated via WSPRecv when the number of bytes read is 0 for byte-stream protocols, or via a return error code of WSAEDISCON for message-oriented protocols. In any case, a WSPRecv return error code of WSAECONNRESET indicates an abortive shutdown.
At connection teardown time, it is also possible (for protocols that support this) to exchange user data between the endpoints. The end that initiates the teardown can call WSPSendDisconnect to indicate that no more data is to be sent and cause the connection teardown sequence to be initiated. For certain protocols, part of this teardown sequence is the delivery of disconnect data from the teardown initiator. After receiving notice that the remote end has initiated the teardown sequence (typically via the FD_CLOSE indication), the WSPRecvDisconnect function may be called to receive the disconnect data (if any).
To illustrate how disconnect data might be used, consider the following scenario. The client half of a client/server application is responsible for terminating a socket connection. Coincident with the termination it provides (via disconnect data) the total number of transactions it processed with the server. The server in turn responds back with the cumulative grand total of transactions that it has processed with all clients. The sequence of calls and indications might occur as follows:
Client Side | Server Side |
---|---|
(1) invoke WSPSendDisconnect to conclude session and supply transaction total | |
(2) get FD_CLOSE, or WSPRecv with a return value of zero or WSAEDISCON indicating graceful shutdown in progress | |
(3) invoke WSPRecvDisconnect to get client's transaction total | |
(4) Compute cumulative grand total of all transactions | |
(5) invoke WSPSendDisconnect to transmit grand total | |
(6) receive FD_CLOSE indication | (5') invoke WSPClosesocket |
(7) invoke WSPRecvDisconnect to receive and store cumulative grand total of transactions | |
(8) invoke WSPClosesocket |
Step (5') must follow step (5), but has no timing relationship with step (6), (7), or (8).
It is important to distinguish the difference between shutting down a socket connection and closing a socket. Shutting down a socket connection involves an exchange of protocol messages between the two endpoints which is hereafter referred to as a shutdown sequence. Two general classes of shutdown sequences are defined: graceful and abortive (also referred to as "hard"). In a graceful shutdown sequence, any data that has been queued but not yet transmitted can be sent prior to the connection being closed. In an abortive shutdown, any unsent data is lost. The occurrence of a shutdown sequence (graceful or abortive) can also be used to provide an FD_CLOSE indication to the associated applications signifying that a shutdown is in progress. Closing a socket, on the other hand, causes the socket handle to become deallocated so that the application can no longer reference or use the socket in any manner.
In Windows Sockets, both the WSPShutdown function, and the WSPSendDisconnect function can be used to initiate a shutdown sequence, while the WSPCloseSocket function is used to deallocate socket handles and free up any associated resources. Some amount of confusion arises, however, from the fact that the WSPCloseSocket function will implicitly cause a shutdown sequence to occur if it has not already happened. In fact, it has become a rather common programming practice to rely on this feature and use WSPCloseSocket to both initiate the shutdown sequence and deallocate the socket handle.
To facilitate this usage, the sockets interface provides for controls via the socket option mechanism that allows the programmer to indicate whether the implicit shutdown sequence should be graceful or abortive, and also whether the WSPCloseSocket function should linger (i.e. not complete immediately) to allow time for a graceful shutdown sequence to complete.
By establishing appropriate values for the socket options SO_LINGER and SO_DONTLINGER, the following types of behavior can be obtained with the WSPCloseSocket function.
One technique that can be used to minimize the chance of problems occurring during connection teardown is to not rely on an implicit shutdown being initiated by WSPCloseSocket. Instead one of the two explicit shutdown functions ( WSPShutdown or WSPSendDisconnect ) are used. This in turn will cause an FD_CLOSE indication to be received by the peer application indicating that all pending data has been received. To illustrate this, the following table shows the functions that would be invoked by the client and server components of an application, where the client is responsible for initiating a graceful shutdown.
Client Side | Server Side |
---|---|
(1) Invoke WSPShutdown(s, SD_SEND) to signal end of session and that client has no more data to send. | |
(2) Receive FD_CLOSE, indicating graceful shutdown in progress and that all data has been received. | |
(3) Send any remaining response data. | |
(5') Get FD_READ and invoke recv to get any response data sent by server | (4) Invoke WSPShutdown(s, SD_SEND) to indicate server has no more data to send. |
(5) Receive FD_CLOSE indication | (4') Invoke WSPCloseSocket |
(6) Invoke WSPCloseSocket |
The timing sequence is maintained from step (1) to step (6) between the client and the server, except for step (4') and (5') which only has local timing significance in the sense that step (5) follows step (5') on the client side while step (4') follows step (4) on the server side, with no timing relationship with the remote party.