A few days ago, I wrote a note detailing how to set up a simple TCP client and server using netcat. Today, I have taken things a step further by capturing packets in Wireshark and providing a step-by-step explanation of how the TCP flow works. In the table below, you can find a general overview of this process.

Flow Packet captured from Wireshark Explaination
client -[SYN]-> server Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 0, Len: 0
Source Port: 24491
Destination Port: 5000
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 0 (relative sequence number)
Sequence Number (raw): 4126488336
[Next Sequence Number: 1 (relative sequence number)]
Acknowledgment Number: 0
Acknowledgment number (raw): 0
1000 …. = Header Length: 32 bytes (8)
Flags: 0x002 (SYN)
Window: 65535
[Calculated window size: 65535]
Checksum: 0xd6b0 [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
First, client says “hi there, I’d like to connect, here is my number xxxxxxx36

When client send a SYN packet to server. Wireshark will show you the relative sequence, or ACK number which is 0. But actually, it is a random number .

client <-[SYN,ACK]- server Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 0, Ack: 1, Len: 0
Source Port: 5000
Destination Port: 24491
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 0 (relative sequence number)
Sequence Number (raw): 547479085
[Next Sequence Number: 1 (relative sequence number)]
Acknowledgment Number: 1 (relative ack number)
Acknowledgment number (raw): 4126488337
1000 …. = Header Length: 32 bytes (8)
Flags: 0x012 (SYN, ACK)
Window: 65535
[Calculated window size: 65535]
Checksum: 0xd7d0 [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
Options: (12 bytes), Maximum segment size, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), SACK permitted
[SEQ/ACK analysis]
[Timestamps]
Server responses “oh sure, I’ve received your number xxxxxxx36. And I add one to keep track, so now it is xxxxxxx37. Please take my number xxxxxxx85
After received the packet from client, server will send its own Sequence number 547479085 and Ackowledgement number.
The Acknowledge number is the client’s Sequence number + 1 which is 4126488337
client -[ACK]-> server Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 1, Ack: 1, Len: 0
Source Port: 24491
Destination Port: 5000
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 1 (relative sequence number)
Sequence Number (raw): 4126488337
[Next Sequence Number: 1 (relative sequence number)]
Acknowledgment Number: 1 (relative ack number)
Acknowledgment number (raw): 547479086
0101 …. = Header Length: 20 bytes (5)
Flags: 0x010 (ACK)
Window: 10233
[Calculated window size: 2619648]
[Window size scaling factor: 256]
Checksum: 0xeace [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
[SEQ/ACK analysis]
[Timestamps]
Client responses “I’ve received your number xxxxxxx85. And I add one to keep track, so now it is xxxxxxx86. We are synced”
Client verifies receiving packet from the server by sending ACK (acknowledge) message.
The ACK number is server’s Squence number + 1, 547479086
client -[PSH,ACK]-> server Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 1, Ack: 1, Len: 34
Source Port: 24491
Destination Port: 5000
[Stream index: 0]
[TCP Segment Len: 34]
Sequence Number: 1 (relative sequence number)
Sequence Number (raw): 4126488337
[Next Sequence Number: 35 (relative sequence number)]
Acknowledgment Number: 1 (relative ack number)
Acknowledgment number (raw): 547479086
0101 …. = Header Length: 20 bytes (5)
Flags: 0x018 (PSH, ACK)
Window: 10233
[Calculated window size: 2619648]
[Window size scaling factor: 256]
Checksum: 0xd07d [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
[SEQ/ACK analysis]
[Timestamps]
TCP payload (34 bytes)
Data (34 bytes)
Now, client starts sending messages with flag PSH meaning “I have packed all the good stuffs, please send it imediately”
Also, Next Sequence Number is expected to be 35 because it is sending out 34 bytes payload. ACK number is still 547479086 because it has not received anything from server
client <-[ACK]- server Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 1, Ack: 35, Len: 0
Source Port: 5000
Destination Port: 24491
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 1 (relative sequence number)
Sequence Number (raw): 547479086
[Next Sequence Number: 1 (relative sequence number)]
Acknowledgment Number: 35 (relative ack number)
Acknowledgment number (raw): 4126488371
0101 …. = Header Length: 20 bytes (5)
Flags: 0x010 (ACK)
Window: 10233
[Calculated window size: 2619648]
[Window size scaling factor: 256]
Checksum: 0xeaac [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
[SEQ/ACK analysis]
[Timestamps]
After receiving the packet, server sends the ACK with previous ACK payload size (34). 4126488337 + 34 = 4126488371
client -[FIN,ACK]-> server Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 35, Ack: 1, Len: 0
Source Port: 24491
Destination Port: 5000
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 35 (relative sequence number)
Sequence Number (raw): 4126488371
[Next Sequence Number: 36 (relative sequence number)]
Acknowledgment Number: 1 (relative ack number)
Acknowledgment number (raw): 547479086
0101 …. = Header Length: 20 bytes (5)
Flags: 0x011 (FIN, ACK)
Window: 10233
[Calculated window size: 2619648]
[Window size scaling factor: 256]
Checksum: 0xeaab [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
[Timestamps]
After sending a note, client terminal is close, so it sends FIN (finish?) and ACK to server. At this time, both Sequence number and ACK number are the same as the above because server did not send anything.
client <-[ACK]- server Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 1, Ack: 36, Len: 0
Source Port: 5000
Destination Port: 24491
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 1 (relative sequence number)
Sequence Number (raw): 547479086
[Next Sequence Number: 1 (relative sequence number)]
Acknowledgment Number: 36 (relative ack number)
Acknowledgment number (raw): 4126488372
0101 …. = Header Length: 20 bytes (5)
Flags: 0x010 (ACK)
Window: 10233
[Calculated window size: 2619648]
[Window size scaling factor: 256]
Checksum: 0xeaab [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
[SEQ/ACK analysis]
[Timestamps]
After receiving the FIN flag, server response with an ACK message + 1.
client <-[FIN,ACK]- server Transmission Control Protocol, Src Port: 5000, Dst Port: 24491, Seq: 1, Ack: 36, Len: 0
Source Port: 5000
Destination Port: 24491
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 1 (relative sequence number)
Sequence Number (raw): 547479086
[Next Sequence Number: 2 (relative sequence number)]
Acknowledgment Number: 36 (relative ack number)
Acknowledgment number (raw): 4126488372
0101 …. = Header Length: 20 bytes (5)
Flags: 0x011 (FIN, ACK)
Window: 10233
[Calculated window size: 2619648]
[Window size scaling factor: 256]
Checksum: 0xeaaa [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
[Timestamps]
Now, server closes its portal “hey client, I’m done with you”. Notice, Seq, and ACK are the same as above because server has not received anything from client.c
client -[ACK]- >server Transmission Control Protocol, Src Port: 24491, Dst Port: 5000, Seq: 36, Ack: 2, Len: 0
Source Port: 24491
Destination Port: 5000
[Stream index: 0]
[TCP Segment Len: 0]
Sequence Number: 36 (relative sequence number)
Sequence Number (raw): 4126488372
[Next Sequence Number: 36 (relative sequence number)]
Acknowledgment Number: 2 (relative ack number)
Acknowledgment number (raw): 547479087
0101 …. = Header Length: 20 bytes (5)
Flags: 0x010 (ACK)
Window: 10233
[Calculated window size: 2619648]
[Window size scaling factor: 256]
Checksum: 0xeaaa [unverified]
[Checksum Status: Unverified]
Urgent Pointer: 0
[SEQ/ACK analysis]
[Timestamps]
“Okay server, I have received your farewell letter so I will increase the ACK # to one “.
Let reverse engineering, Client’s seq:36, in which we know it has sent 1 byte for SYN, 1 byte for FIN, and the rest are the payload. Client’s ack:2 shows us that it received 1 SYN and 1 FIN from server
Also, Server’s seq:1 means it has sent 1 byte for SYN, and probally closes. That is why we don’t see the 2 seq. Server’s ack:36 shows that clent sent 1 SYN, 1 FIN, and 34 bytes of payload.