Professional Documents
Culture Documents
Quadrant 1 – e-text
Starting from the previous module, we are on a journey to understand the working
principles of TCP. You must have got an idea of what is expected from TCP, from the
overview that was presented. In this module, we focus on two aspects of TCP – the state
diagram that depicts the connection establishment and termination, and flow control. Thus,
the learning objectives for this module are given below.
Learning Objectives
Connection-oriented mechanism
o To ensure presence of receiver before Tx
Flow control
o To handle the slow-receiver problem
Retransmission
o To take care of lost or erroneous packets
Congestion control
o To take care of the bottleneck at the network
To understand this state transition diagram, let us look at a typical TCP connection
establishment scenario in a client-server setting. We will alternately examine what
happens on the client side and the server side as this process goes. Note that events that
cause transitions may be due to the application process issuing a command or due to TCP
segments received from the other side.
9.2.1.1 Connection Establishment
Normally, it is the server which first opens shop, waiting for clients to request a connection.
So, a server program does the first operation – it performs a passive open. This causes
TCP to move from the ‘closed’ state to the ‘Listen’ state. It waits in this state until it
receives some input from the client side. The connection establishment part of the state
diagram is given in Fig.9.3 with the server-side and client-side activities in different colours
(black for server side events, violet for client side, and red for the special scenario).
Figure 9.3 Connection Establishment
Now, let us say, a client wants to connect to this particular server program. So, the client
now does an active open specifying the details of the server that it wants to connect to.
This causes the client side TCP to start the 3-way handshake to open a connection with
the server. It sends a SYN segment to the server, and TCP transits from the closed state
to the ‘SYN_SENT” state.
The server which is in the “Listen” state, receives the SYN segment. This event causes it
to respond with a SYN+ACK segment, and the server now moves to the SYN_RCVD
state.
The SYN+ACK segment reaches the client which is waiting in the SYN_SENT state. On
receiving the SYN+ACK, it sends an ACK (the third step of the 3-way handshake) and
moves into the connection “ESTABLISHED” state, where it can send and receive data.
On receiving the ACK segment, the server which is now waiting in the SYN_RCVD state,
moves to the “ESTABLISHED” state, and begins to send and receive data.
In addition to this normal sequence of operation, a server-side TCP which is in the “Listen”
state, may be asked by its application to “Send” data to a specific client (shown in red in
Figure 9.3). In that case, the server side TCP sends a SYN segment to that client, and
moves to the “SYN_SENT” state. In that state, when it gets a SYN+ ACK from the other
end, it moves to the “Established” state after sending an ACK.
Now it possible that when TCP is in the SYN_SENT state, it may receive a SYN from the
other end. (A possibility where both ends are trying to connect with each other – shown in
red in Figure 9.3). In that case, it responds by sending a SYN+ACK, and moves to the
SYN_RCVD state, from which it will move to the ESTABLISHED state after receiving an
ACK.
9.2.1.2 Connection termination
When it comes to terminating the connection, remember that we have three different
scenarios : (1) One side (either client or server), say side A, closes the connection first,
and the other side, say side B closes the connection. A sends a FIN segment, gets an
ACK from B, then B sends a FIN, and gets an ACK from A.
(2) Both sides close the connection almost simultaneously, i.e ., both sides send FIN to
each other – which cross each other. The two sides then respond by sending the
respective ACKs.
(3) Side A sends a FIN. Just when it receives the FIN, and is about to send an ACK, side B
also decides to close the connection. So it sends a FIN+ACK segment to A. A responds
with an ACK.
We will look at each of these 3 scenarios in detail.
Scenario 1 : The state transitions for scenario 1 are given in Figure 9.4. Actions of side A
are shown in black, and that of B in violet.
TCP TCP
La s tByte Writte n La s tByte Rea d
Figure(a9.7
) Sending and receiving buffer management
(b)
Action at A Action at B
…. ……
At this point, side A has sent all of the 2500 bytes of data written by its application. If it has
more data to be sent, it could write another 2500 bytes in the buffer, as all data transmitted
is acknowledged, but it will not be able to send more than 500 bytes. (Why ? Look at the
AWS).
You can work out different scenarios to figure out how the data flow is controlled
depending on the buffer availability at both ends. Suppose the application at A wants to
write another 1000 bytes into the buffer, (at this point, i.e., after it has sent its 500 bytes,
will it be able to do so ? (Is there space in the buffer to hold 1000 new bytes?)
If we explore these different scenarios, we will see that certain very peculiar situations can
arise, which totally affect the performance of the network. We will look at one such
scenario that was faced by TCP as it evolved, and some solutions to this. The
phenomenon that we are referring to is the Silly Window Syndrome (SWS) which is
explained below.
9.4 Silly Window Syndrome (SWS)
Consider this situation. Let us say that A wants to send 2500 bytes of data to B. B is not
interested in sending any data to A, only ACKs. B has a MaxRecvBuffer of 2000 bytes, It
gives a AWS of 2000, and A sends 2000 bytes (in 4 segments), but the application at B
does not read any data. It is so slow. Now when the ack is sent for the 2000 bytes, the
advertised window size will be “0”. No more place new data. Now, look at the situation.
A cannot send data until it gets a non-zero AWS from B. B is not going to send any ACK
( and along with it the AWS) if it does not receive any data from A. So, a deadlock occurs –
A cannot send data until it gets non-zero AWS from B, and B cannot send AWS until it
receives some data from A. So both get stuck.
A simple solution to this deadlock, is for A to maintain a small timer in such a situation (i.e.,
after it gets an AWS=0). Once this timer expires, A can send a small – one byte - “probe”
segment to B. If by this time, B has read some data, the window can be opened. There will
be place in the buffer for new data, and B can advertise a non-zero AWS, and A will now
be able to proceed sending data. We use a 1-byte probe segment to ensure that we do not
lose too much data if the buffer is still full. So this is like a feeler – just send little data and
see how B responds. If B has not read any data, this 1-byte will be dropped, and A has to
send a probe segment again after some time.
Now this is not the end of the problem. Suppose, when B receives the one-byte probe
segment, it has read exactly one byte of data from the buffer. Then, the data from A will be
stored in that available 1-byte, and an ACK will be sent with AWS = 0. Now, A again will
send a probe segment after some time, and the same scenario could repeat. B receives
the 1-byte, and sends an ACK with AWS=0, and so on. So what is happening is that data
is going from A to B, but in 1-byte segments which are sent at intervals of probe-segment
timer. The window based flow control is reduced to a 1-byte stop-and-wait flow control and
that too which triggers only periodically. This degeneration of the window-based scheme to
sending small-sized segments is called the “Silly Window Syndrome” (SWS). The
performance suffers as the overhead for every byte of data becomes very high (20bytes
minimum).
This is a case of receiver causing SWS. Of course, we gave an extreme scenario of
sending 1-byte at a time, but advertising small windows (after an AWS of zero), will also
lead to this SWS.
SWS can also be caused by the sender. This happens when the sending application writes
one byte at a time, that too slowly. Its TCP will then begin to transmit small sized
segments. This is referred to as Sender induced SWS.
Clearly, SWS needs a solution as it affects performance.
9.4.1 SWS solutions
The solution to this problem, could come either from the receiver side, or the sender side,
depending on who caused it. From the receiver side, one straight-forward solution is to not
advertise small windows after advertising a zero window. It could wait for some
considerable space, say, equal to an MSS (maximum segment size) before advertising a
non-zero window.
Alternately, the receiver could delay sending its ACKs. Delay the ACK until some space is
freed in its buffer. But this could cause other issues. For instance, if the ACK is delayed for
too long, sender may time-out and retransmit the packet – unnecessary retransmission !
So, the delay should not be too high, and it is difficult to determine this value.
On the sender side, we have a solution proposed by Nagle, called Nagle’s algorithm.
Nagle’s Algorithm
This algorithm tries to reduce transmission of small sized segments, even if data is being
written very slowly by the sending application, by delaying the sending of data. The trick is
to determine the right amount of time for which you could delay sending of data. If the
delay is too long, it will hurt interactive applications, which may send small amounts of
data, and wait for response. If the delay is too small, it obviously affects performance. So,
what Nagle’s algorithm does is, that it comes up with a self-clocking scheme to determine
when data is to be transmitted. It works like this :
When application generates additional data,
If it fills a max segment (data > 1 MSS), and if the window is open, it is sent;
else
if there is unacknowledged data in transit, (some data has been sent, but ACK not
rcvd), then it is buffered until the ACK arrives, and sent when the ACK arrives;
else (if there are no pending ACKs), it is sent even if it is < MSS.
The idea of checking for unACKed data, and using the ACK as a trigger to transmit the
data, is where the “self-clocking” idea comes in. If there is some ACK to be received, then
there is some activity going on, so you can afford to wait for some time (upto 1 RTT -
Round-trip-time) before transmitting the newly generated data !
And this helps to reduce sending small-sized segments.
Let us look at an example to better understand this.
Consider sender A generating data at the rate of 10 bytes/sec. Assume MSS = 250, RTT
= 3.5 sec.
Assume that 10 bytes are written into the buffer every 1 sec starting at t=1sec. At t=1 sec,
there are no pending ACKs, hence, a segment consisting of these 10 bytes is sent. The
ACK for this segment will arrive at 4.5 secs. You can guess what will happen now. (Upto
4.5 sec, all data written will be buffered, as per Nagle’s algorithm.)
At t=2 secs, 10 bytes arrive at the buffer. They are not sent, they are held in the buffer, as
we have an ACK pending for the first segment transmitted.
Same at t=3 secs, and t= 4secs. We now have 30 bytes buffered (still less than MSS). At
4.5 secs, when the ACK for the first segment arrives, a segment with these 30 bytes is
sent. We have avoided sending 3 10-byte segments, but there is some delay !
TCP actually allows the application to turn-on this algorithm or turn-it-off depending on
whether it can tolerate this delay or not.
That brings us to the end of the discussion on TCP’s flow control technique.
9.5 Summary
To summarize, we have discussed two major components of TCP – the TCP state
diagram with respect to Connection establishment & termination, and TCP’s flow
control mechanism including buffer management, calculation of window sizes, silly
window syndrome, and its solution Nagle’s algorithm. We will look at other components
of TCP in subsequent modules.
Thank you !
References
1. Computer Networking: A Top Down Approach Featuring the Internet, 6th edition.
Jim Kurose, Keith Ross, Addison-Wesley, 2012.
2. Computer Networks: A systems Approach, 5th edition, David Peterson, Davie,
Morgan Kauffman, 2012.