A server application based on TCP waits for incoming connections on specific Layer 4 ports (see “bind()” in the “Sockets” section, which follows this section). A client requesting an application sends a TCP SYN to one of these ports and performs a TCP handshake with the server (see Chapter 7 for details about the TCP handshake). Example 2-1 shows which ports the server is listening to by using the command netstat –a. The previous command also displays information about the send and receive queue.
Example 2-1 shows, among others, the following servers: an Apache HTTP server configured for SSL (see the line :https), a DNS server (see the line :domain), a Telnet server, and an FTP server.
Example 2-1 Determining the Ports a Server Is Listening To
[root@localhost admin]# netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
The typical connection status that you can observe is either LISTEN (before the connection is established), TIME_WAIT (right after the connection has been closed), or ESTABLISHED if the connection is active. In Example 2-1, you can see a Telnet connection to this server from the client 10.20.5.15.
The server can take a number of possible states, including LISTEN, TIME_WAIT, and ESTABLISHED. Figure 2-3 shows the TCP state machine for reference.
Figure 2-3 TCP State Machine with Highlighted Sequence of States Taken by a Server
The bold arrows show the typical states taken by a connection on a server: At the reception of a SYN, a server responds with a SYN ACK, which brings the state to SYN-RCVD (passive open). After receiving one ACK, the connection is in the ESTABLISHED state.
From the ESTABLISHED state, the typical server connection closure is initiated by the client (passive close).
Connections often can be stuck in a state, as described in the following list, and this is the symptom of a problem:
•
SYN-RCVD—The server has received a SYN (passive open), and it has sent a SYN ACK but has not received an ACK back from the client. Among the possible causes is an asymmetric traffic path. The traffic from the client hits a device that performs NATclosed
Client and Server Packet Processing 39
on the destination IP to the real server IP address. The traffic from the server instead could bypass the device that translates the IP address. As a result, the client does not recognize the source of the SYN ACK.
•
SYN-SENT—The server has sent a SYN (active open) but has not received a SYN ACK from the client. Among the possible causes, the routing could be misconfigured.•
FIN-WAIT1—The server has sent a FIN but has not received an ACK or a FIN ACK.Among the possible causes for this problem, the client could be down as the result of either an administrative action (power cycling) or a failure.
The previous list shows that analyzing the output of the netstat –a command can help you detect problems that relate either to a network misconfiguration (routing issues) or to an anomaly on the client. For more details about the other possible states of a connection, refer to the book TCP/IP Illustrated, by Richard Stevens (Addison-Wesley, 1994).
The closure of the TCP connection can take the form of a FIN handshake or a TCP RST (see Chapter 7). When either side of a connection sends a TCP FIN, the other entity can finish sending the content of its send buffer and eventually close the connection.
When either the client or the server sends a TCP RST, it means that the connection is closing, and the data left in the send buffer of either entity is discarded. Under normal conditions, either side of an application should close connections with the TCP FIN sequence, but there are exceptions; for example, some browsers use TCP RSTs.
For some applications, receiving a TCP RST is the symptom of a failure on the client side.
As a result, these applications can throw an exception when they see this type of closure.
This is sometimes the case for servlet engines (see the Chapter 3 for more information on servlet engines).
Sockets
Sockets provide application processes with a protocol-independent interface to the network communication. In UNIX, the communication between the process and the OS (kernel) uses system calls.
The following list shows the sequence of system calls used by a server that uses TCP as the transport protocol:
1 Socket()—Creates a socket for streams (TCP). The socket descriptor created on the server defines the capability of the server to accept connections of a specific type, for the IP address defined by the Bind() call.
2 Bind()—Associates the socket with a local IP address and Layer 4 port number.
3 Listen()—Defines the length of the receive queue for incoming connection requests.
4 Accept()—Used by the server to wait for incoming connection requests. This call puts the process in a waiting state for incoming connections. When a new connection request is received, the accept call returns a new socket descriptor. This descriptor references a specific client connection to the server.
5 Read()/Write()—Exchange data between the server and the client.
Client applications based on TCP use the socket() and connect() calls to establish the connection to the server, and write() and read() calls to exchange data.
Server applications based on UDP use different system calls than those listed because UDP does not establish connections between the client and the server. As a result, there is no need to use the Listen() and Accept() system calls on a UDP server. The following list shows the sequence of system calls used by a server using UDP as the transport protocol:
1 Socket()—This call creates a socket descriptor of the datagram type.
2 Bind()—This call binds the socket descriptor to an IP address and a port.
3 Recvfrom()—A process calling recvfrom() waits for incoming connections. When UDP datagrams arrive, recvfrom() returns the IP address of the client together with the datagram.
4 Sendto()—This call sends datagrams to the IP address specified in the parameters to this call.
Sockets allow options to be defined to control the TCP and UDP functions in the kernel, such as these:
•
SO_KEEPALIVE—This option controls the capability of TCP to verify whether an idle connection is still alive by sending a keepalive probe after a configurable amount of time (the default is 2 hours). If no ACK is received, the socket is closed. For more information, see the section, “TCP Timeout.”•
SO_RCVBUF—TCP or UDP receives buffer size. This buffer size is used as the receive window by the TCP protocol during the handshake.•
SO_SNDBUF—TCP or UDP send buffer size.Server applications that enable the SO_KEEPALIVE option should configure an appropriate TCP KEEPALIVE. Under normal conditions, for many applications a TCP connection is never idle for 2 hours. The implication of using the default setting is the possibility of keeping servers’ resources allocated for clients that did not close connections.
The receive buffer size has a direct implication on the performance of TCP transfers. Suppose that the two communicating entities are host A and host B, and suppose that the receive buffer configured on host B is 64 KB. Assuming that the maximum segment size (MSS) is 1460 bytes, host A can send 44 segments (64 KB/1460 bytes, rounded to an even number