DEV Community

Khalif AL Mahmud
Khalif AL Mahmud

Posted on

How I Used Wireshark to Dissect a Real TCP Connection — From Handshake to Teardown

Most people who study networking learn TCP from diagrams and textbooks. But there is a real difference between reading about the three-way handshake and actually watching it happen — byte by byte — in a live packet capture.

I spent a session doing exactly that: loading a real .pcap trace into Wireshark, expanding TCP headers, filtering traffic, reading sequence numbers, and tracing the full lifecycle of a TCP connection — from the first SYN all the way to the RST teardown.

This article walks through everything I observed. If you have Wireshark installed (it ships with Kali Linux), you can follow along with any .pcap file and see the same patterns yourself.


What Is a PCAP File and How Do You Open One?

A .pcap (packet capture) file is a recorded snapshot of network traffic. Wireshark can open these files and let you inspect every packet as if the traffic was live.

To open one:

wireshark trace-tcp.pcap
Enter fullscreen mode Exit fullscreen mode

Or from the GUI: File → Open → select your .pcap file

Once loaded, you will see a three-panel view:

  • Top panel — packet list (number, time, source, destination, protocol, info)
  • Middle panel — protocol layers of the selected packet (expandable)
  • Bottom panel — raw hex bytes

The Trace I Analyzed

The capture contained 1172 packets of a real HTTP download over TCP. Two IP addresses were involved:

Role IP Address
Client (my machine) 192.168.1.122
Remote web server 64.238.147.113

The client fetched a PDF file from a web server on port 80. The trace covers the full TCP session: connection setup, data transfer, and teardown.


Step 1: Inspecting a TCP Segment's Header Fields

I selected a long packet from the middle of the trace (one of the 1434-byte data segments) and expanded the Transmission Control Protocol section in the middle panel.

Here is what each field tells you:

Field What it means
Source Port Port on the sender's side (port 80 = web server)
Destination Port Port on the receiver's side
Sequence Number Position in the byte stream of the first payload byte
Acknowledgement Number Next expected byte from the other direction
Header Length Size of the TCP header in bytes
Flags Control bits: SYN, ACK, FIN, RST, PSH, URG
Window Size How much buffer space is available at the receiver
Checksum Error detection value
Options Negotiated parameters like MSS, timestamps, SACK
Payload The actual data being transferred

The Urgent Pointer field exists in the header but was zeroed out in every packet I saw — it is rarely used in modern TCP connections.


Step 2: Understanding the TCP Segment Structure

The TCP segment layout looks like this:

|  Source Port (2B)  |  Dest Port (2B)  |
|       Sequence Number (4B)            |
|    Acknowledgement Number (4B)        |
| Header Len + Flags (2B) | Window (2B) |
|   Checksum (2B)  |  Urgent Ptr (2B)  |
|       Options (variable, if any)      |
|            Payload (N bytes)          |
Enter fullscreen mode Exit fullscreen mode

A few things to note from Wireshark:

  • Header Length and Flags are packed together into 2 bytes — Wireshark separates and labels them for you
  • Options were present in most packets and were always a multiple of 4 bytes in length
  • Payload was absent on pure ACK segments (the ACK-only packets are typically only 66 bytes)


Step 3: The Three-Way Handshake

To filter only SYN packets:

tcp.flags.syn == 1
Enter fullscreen mode Exit fullscreen mode

Here is what I observed in the first three packets:

Packet Direction Flags Seq Ack
1 (t=0.000000) Client → Server SYN 0
2 (t=0.088010) Server → Client SYN, ACK 0 1
3 (t=0.088080) Client → Server ACK 1 1

Then immediately after packet 3, the client sent the HTTP GET request (packet 4, t=0.088579).

Key observations:

  • The initial SYN carries no ACK number — it is the first message, so there is nothing to acknowledge yet
  • Wireshark shows relative sequence numbers (starting from 0), not the actual 32-bit values negotiated at the start
  • The ACK number is always the received Seq number + 1
  • The RTT (Round Trip Time) between SYN and SYN-ACK was 88 ms in this trace
  • The third packet (ACK) and the HTTP GET (data) were sent in separate packets even though they could theoretically be combined

Step 4: TCP Connection Options

The SYN packets also negotiate TCP options. I expanded the Options section and found:

Option Purpose
Maximum Segment Size (MSS) Tells the other side the largest segment it can receive
Window Scale Scales up the window size field beyond 65535 bytes
SACK Permitted Enables selective acknowledgements for better loss recovery
Timestamps Used to estimate RTT on each packet
NOP / End of Option List Padding — used to align options to 4-byte boundaries

Both sides advertised these options in their SYN. MSS was only sent on the SYN (it does not change), while Timestamps were included on every data packet to keep a fresh RTT estimate.


Step 5: FIN Teardown

To find the teardown, I scrolled to the end of the trace. In this particular capture, the connection was torn down with a RST (Reset) rather than a graceful FIN exchange.

Packet Direction Flags Seq Ack
Last Client → Server RST 146 1056827

Points worth noting:

  • RST teardown is abrupt — no acknowledgement is needed from the other side
  • A FIN-based teardown (when it happens) is symmetric, similar to the handshake: each side sends a FIN and ACKs the other's FIN
  • In a FIN exchange, the FIN flag occupies one sequence number (just like SYN does), so the ACK is always FIN Seq + 1

Step 6: Analyzing the Data Transfer with IO Graphs

To visualize throughput over time:

Statistics → IO Graph

Configuration I used:

  • X-Axis: Tick interval = 0.1 sec, Pixels per tick = 10
  • Y-Axis: Unit = Bits/Tick
  • Graph 1 filter: tcp.srcport == 80 (download traffic)
  • Graph 2 filter: tcp.dstport == 80 (upload/ACK traffic)

What I saw:

  • Download started slow and ramped up exponentially — this is TCP slow start in action
  • Once running at full speed, throughput settled around 2.5 Mbps (250 packets/sec)
  • Upload was a thin, steady line of ACK traffic: about 120 packets/sec, ~60,000 bits/sec
  • The download finished cleanly with no visible retransmission events

The data packets were 1434 bytes each, of which 1368 bytes were TCP payload. That means ~95% of the download was actual content — very efficient.


Step 7: Delayed ACKs and Flow Control

Looking at the middle section of the trace, I noticed the client was not ACKing every single data packet. Instead, one ACK was sent for roughly every two received data segments. This is Delayed ACK — a standard TCP optimization that cuts the number of ACK packets in half.

I also observed the Window Size field on every segment. Throughout the download, the window stayed well above zero. If it ever hits zero, TCP enters a flow control stall — the sender is blocked until the receiver empties its buffer and advertises a non-zero window.

During the download, since the client was only receiving:

  • The sequence numbers of incoming server packets kept increasing
  • The ACK numbers in the client's outgoing packets increased to match
  • The sequence number of client's outgoing packets stayed flat (no new data being sent)

How to Verify Your Own Trace

If you open any .pcap of HTTP traffic, you can verify these same patterns:

# Filter three-way handshake
tcp.flags.syn == 1

# Filter only download traffic (from web server)
tcp.srcport == 80

# Filter only upload/ACK traffic (to web server)
tcp.dstport == 80

# Find RST teardown
tcp.flags.reset == 1

# Find FIN teardown
tcp.flags.fin == 1
Enter fullscreen mode Exit fullscreen mode

Use Statistics → IO Graph with Bits/Tick on Y-axis to observe slow start and steady-state throughput.


My Full Observation Table

Here is a summary of all observation points I identified in the trace:

Obs. Packet No. Time Description
a 1 0.000000 Client sends SYN — initiates TCP connection
b 2 0.088010 Server replies with SYN-ACK
c 3 0.088080 Client sends ACK — handshake complete
d 4 0.088579 Client sends HTTP GET request
e 5 0.177819 Server ACKs the HTTP GET
f 6 0.178321 Server begins sending HTTP response (PSH+ACK)
g 7 0.178388 Client ACKs first data segment
h 8 0.189114 Server sends another TCP data segment
i 9 0.266705 Server continues streaming data segments
j 10 0.266787 Client sends delayed ACK for previous segments

What I Learned

Doing this kind of hands-on analysis changed the way I think about TCP. A few things that stood out:

Relative vs absolute sequence numbers — Wireshark shows you 0-based numbers by default. The real sequence numbers are large random 32-bit values chosen at connection time. Always check whether you are looking at relative or absolute numbers.

RTT from packet timestamps — You can measure the RTT directly from the trace without any extra tools. The gap between SYN (packet 1) and SYN-ACK (packet 2) was exactly 88ms, which matched the FIN exchange RTT too.

Slow start is visible — The IO Graph ramp from 0 to 2.5 Mbps is not gradual — it has the characteristic exponential curve of TCP slow start. This is not a network artifact, it is the protocol deliberately probing for available bandwidth.

Efficiency is high — 95% of the download bytes were actual payload. The overhead from headers and ACK packets was small.

RST vs FIN — Graceful FIN shutdown is symmetric and takes at least one round trip. RST is a hard cut that requires no acknowledgement. Both are normal and you will see both in real traffic.


Common Mistakes to Avoid

Mistake What Actually Happens
Confusing sequence and ACK numbers Seq = my data position; ACK = what I expect from you next
Assuming Wireshark shows real Seq numbers It shows relative numbers by default — enable absolute in preferences if needed
Using TCP Stream Graph for receiver-side traces Those graphs assume you captured at the sender — use IO Graph instead
Ignoring the Window field A zero window stalls the connection entirely
Expecting one ACK per packet Delayed ACK means typically one ACK per two data packets
Treating RST and FIN as the same RST is abrupt (no handshake); FIN is graceful (symmetric exchange)

Conclusion

Wireshark turns abstract protocol concepts into something you can see and measure. The three-way handshake, slow start, delayed ACKs, flow control, and connection teardown — they are all there in the packets if you know what to look for.

If you have never done a trace analysis like this, I would encourage you to download any .pcap from a public dataset and try the filters from this article. The patterns are consistent across real traffic.

The next time someone mentions TCP, you will not just remember the diagram — you will remember what the bytes actually looked like.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.