During my computer networks class a friend of mine asked me to give a quick overview of how TCP connections work. Without going into congestion control, timeouts, etc, I decided to bring up a sample TCP connection trace and go through the steps of requesting data from a web server. I dropped it here in case it could be useful to anyone else.
1. First let’s listen in on connections to and from port 80 (web server):
tcpdump -n port 80 -l > tcpdump.txt
2. On another terminal let’s make a GET request to a website (example.net) using netcat:
printf "GET / HTTP/1.1\r\nHost: example.net\r\n\r\n" | nc example.net 80
3. Now let’s examine our tcpdump.txt
file:
(I removed some noise from the output to focus on what we’re describing)
start connection
The following are the steps for the initial ‘handshake’, where the client (10.0.2.15.43830) tries to establish a connection to the server (93.184.216.34.80). The ‘S’ flag represents an attempt to send some message, and the ‘.’ flag is the ACKnowledgement that a message was received (based on seq #). When possible, both are packaged together as a response + acknowledgement.
IP 10.0.2.15.43830 > 93.184.216.34.80: Flags [S], seq 3558958912, win 29200, length 0
IP 93.184.216.34.80 > 10.0.2.15.43830: Flags [S.], seq 2944001, ack 3558958913, win 65535, length 0
IP 10.0.2.15.43830 > 93.184.216.34.80: Flags [.], ack 1, win 29200, length 0
The client asks ‘Can we connect?’; the server says ‘Got your message, ready to connect’; client responds with ‘Got it.’
end of three-way handshake
sending the GET request
The client sends the actual GET request. You can see that the length isn’t 0 anymore and then the ‘F’ bit signals the end of data being transmitted and that the host is ready to disconnect.
IP 10.0.2.15.43830 > 93.184.216.34.80: Flags [P.], seq 1:38, ack 1, win 29200, length 37
IP 10.0.2.15.43830 > 93.184.216.34.80: Flags [F.], seq 38, ack 1, win 29200, length 0
The server responds with an acknowledgement for both of these messages.
IP 93.184.216.34.80 > 10.0.2.15.43830: Flags [.], ack 38, win 65535, length 0
IP 93.184.216.34.80 > 10.0.2.15.43830: Flags [.], ack 39, win 65535, length 0
response data from the server
The server responds with a big chunk of data (in this case its the home page of example.net
).
IP 93.184.216.34.80 > 10.0.2.15.43830: Flags [P.], seq 1:1593, ack 39, win 65535, length 1592: HTTP: HTTP/1.1 200 OK
The client acknowledges that it received that data.
IP 10.0.2.15.43830 > 93.184.216.34.80: Flags [.], ack 1593, win 31240, length 0
Now its the server’s turn to signal that it is ready to disconnect.
IP 93.184.216.34.80 > 10.0.2.15.43830: Flags [F.], seq 1593, ack 39, win 65535, length 0
& the client acknowledges it.
IP 10.0.2.15.43830 > 93.184.216.34.80: Flags [.], ack 1594, win 31240, length 0
end of connection teardown
- An important thing to note is that a host can still receive data once it sends the F bit, but it can no longer send anything (only ACKs).
- The sequence number is initially random during the handshake phase, but its then the size of the chunk of data being sent + the current sequence number at this point in the connection. For example when the server sends 1592 bytes of data, the following acknowledgement number from the client is 1593. The next piece of data sent from the server will start at 1593.