▦Packet Report

Compare packet-capture latency without confusing RTT, response time and packet gaps

A Wireshark and TShark workflow for comparing TCP RTT across captures, checking capture quality and separating network delay from application waits.

Packet Report Editorial Team · 8 min read

To compare network latency in packet captures, measure the same exchange, from the same capture location, under comparable conditions. For TCP, start with data-to-ACK timing—not the gap between arbitrary packets—and compare a distribution of samples rather than one unusually slow packet.

This workflow uses Wireshark and TShark for TCP traffic you own or are authorized to inspect. It does not apply directly to QUIC or arbitrary UDP traffic.

Choose the interval before measuring it

“Latency” can describe several different intervals:

Measurement Events to match What the interval includes
TCP handshake response Client SYN → corresponding server SYN-ACK, observed near the client Outbound and return travel, plus the responder’s handling of the SYN
TCP ACK RTT Data segment → corresponding ACK, observed near the data sender Outbound and return travel, plus receiver ACK delay
Application response time Defined request boundary → corresponding response boundary Network travel, service processing and any intervening waits
One-way transit time Same packet at two capture points Transit between those points, subject to clock and timestamp uncertainty

A packet-list time delta is simply a gap between observations. Unless the two packets represent a matched exchange, it is not a latency measurement.

TCP ACK timing is also not pure network propagation time. TCP receivers can deliberately delay acknowledgments and acknowledge multiple segments together; RFC 9293 explains delayed ACK behavior. A larger data-to-ACK interval can therefore reflect the path, the receiver or both.

1. Make the captures comparable

For a before-and-after test, keep these conditions fixed where possible:

  • Capture point and direction: use the same client interface or the same external observation point. Separate client-data/server-ACK samples from server-data/client-ACK samples.
  • Destination: verify the actual endpoint. A hostname alone is not enough to establish that both runs reached the same server.
  • Workload: repeat the same operation, with similar request sizes, concurrency and background load.
  • Connection state: compare new connections with new connections, and reused connections with reused connections. Separate startup from steady-state transfer.
  • Analysis settings: use the same Wireshark/TShark version and TCP preferences for both files.

Capture both directions and begin before connection establishment when possible. Check the capture’s drop information if available, and look for missing sequence ranges. Absence of a recorded drop count does not establish that the capture is complete.

Host captures also need an offload check. Segmentation and checksum offloading can produce unusually large captured packets or apparent checksum errors that do not represent packets as transmitted on the wire. The Wireshark offloading guide explains these artifacts. Keep offload conditions consistent; do not change production NIC settings merely to make a trace look cleaner.

Finally, displayed precision is not timestamp accuracy. Wireshark uses timestamps supplied by the capture system, and their accuracy depends on that system. Nine decimal places do not establish nanosecond accuracy. See Wireshark’s timestamp documentation.

If the observation point is still undecided, see how to capture packets from a wireless client.

2. Inspect one TCP exchange in Wireshark

Open the first capture and locate the relevant connection. Statistics → Conversations, on the TCP tab, helps identify endpoint pairs and traffic volumes. Its duration column describes the conversation’s duration—not RTT. Wireshark documents the conversation statistics here.

Ensure the TCP preference Analyze TCP sequence numbers is enabled. Select a packet in the connection and inspect its tcp.stream value. Then apply a display filter such as:

tcp.stream == 7 && tcp.analysis.ack_rtt

Here, 7 is an example stream number. Select the matching connection independently in the other file; stream numbers are local to each capture, not persistent connection identifiers. An empty result does not mean zero latency: check the stream selection, analysis preference and whether both directions were captured.

For one displayed ACK:

  1. Expand Transmission Control Protocol → SEQ/ACK analysis.
  2. Find tcp.analysis.ack_rtt, labeled “The RTT to ACK the segment was.”
  3. Find tcp.analysis.acks_frame, which identifies the segment Wireshark matched to that ACK.
  4. Double-click that frame link and inspect the segment’s direction, sequence range and timestamp. If the ACK-only filter hides it, temporarily clear the filter and go to the referenced frame number.

These are generated analysis fields, not RTT values carried in the TCP header. The TCP field reference defines them, and the packet-details guide explains generated fields and frame links. You can right-click the RTT field and apply it as a column for easier inspection.

The filter selects matched ACK intervals, not a guaranteed data-only sample set. Check the referenced segment: SYN and FIN exchanges belong in separate phases, and retransmitted data may make the match ambiguous. Filtering on the ACK packet’s tcp.len does not establish whether the segment it acknowledges carried data.

For arithmetic only, suppose a synthetic client-side trace records a data segment at 10.000 s and its corresponding ACK at 10.024 s:

Observed ACK RTT = 10.024 − 10.000 = 0.024 s = 24 ms

That is the observed data-to-ACK interval, including any receiver ACK delay. It does not establish a 12 ms one-way path.

Capture location changes the meaning. For client-originated data, a capture near the client observes the trip to the TCP peer and back. Near the server, the same data-to-ACK pair mainly shows the server’s local acknowledgment turnaround. At a midpoint, it covers the remaining trip toward the receiver and back to that midpoint. Do not pool those measurements as equivalent RTTs.

3. Compare distributions, then inspect the slow samples

With a packet in the connection selected, open Statistics → TCP Stream Graphs → Round Trip Time. Check the plotted direction and use the same sampling method for both captures.

Sampling matters: Wireshark’s RTT graph can calculate values for all data packets, use SACK information, or restrict the plot to packets with matching RTT fields. Choose Data Packets matching RTT when comparing the graph with exported tcp.analysis.ack_rtt samples, and restrict the export to the same data-transfer phase. If your version offers Data Packets matching Karn RTT, that option excludes ambiguous ACKs under Karn’s definition; apply the same exclusion to your exported samples before comparing them. The RTT graph documentation describes these choices.

For each comparable direction and test phase, record:

  • Sample count and measurement duration.
  • Median ACK RTT for typical behavior.
  • 95th percentile ACK RTT for the slower tail, provided the sample is large enough to make it useful.
  • A low percentile or minimum as context—not as a guaranteed propagation floor.
  • Retransmission and zero-window episodes separately.

Repeat the workload across several runs. One long, busy connection should not silently outweigh every short connection in a pooled comparison. Either compare like-for-like connections or report per-run summaries as well as the pooled samples.

Then return to the packets around the slow tail. Use this diagnostic filter within the stream:

tcp.stream == 7 && (
  tcp.analysis.retransmission ||
  tcp.analysis.fast_retransmission ||
  tcp.analysis.spurious_retransmission ||
  tcp.analysis.out_of_order ||
  tcp.analysis.zero_window
)

Treat the flags as analysis leads, not verdicts. Wireshark processes TCP packets in capture-file order, and its interpretations can vary with capture location and available context. A zero window means the receiver has advertised that it cannot accept more data—a flow-control pause, not simply a slow path. See Wireshark’s TCP analysis guide.

Do not silently discard retransmission stalls to produce a cleaner latency number. Report unambiguous ACK timing separately from loss-recovery behavior. RFC 6298 explains why acknowledgments following retransmission can be ambiguous: the ACK may correspond to the original transmission or a later copy.

4. Export the same fields for both files

For repeatable comparisons, export ACK timing with TShark. This example reads a saved file and writes metadata only:

tshark -2 -n -r before.pcapng \
-o tcp.analyze_sequence_numbers:TRUE \
-Y 'tcp.stream == 7 && tcp.analysis.ack_rtt' \
-T fields -E header=y -E separator=, -E quote=d \
-e frame.number \
-e frame.time_relative \
-e tcp.stream \
-e tcp.srcport \
-e tcp.dstport \
-e tcp.analysis.acks_frame \
  -e tcp.analysis.ack_rtt > before-rtt.csv

Repeat for after.pcapng, using that file’s matching stream number. The TShark manual documents two-pass analysis, display filtering and field export.

This exports the raw matched-ACK sample set. In Wireshark/TShark 4.6 and later, append && !tcp.analysis.ambiguous_ack to the -Y expression to exclude ACKs flagged as Karn-ambiguous. The field reference lists that field and its supported versions. On older versions, inspect retransmission-affected exchanges before describing the samples as unambiguous; simply excluding retransmission packets from the ACK filter is not sufficient.

The RTT values are in seconds; multiply by 1,000 for milliseconds. Use the ports and your connection mapping to separate ACK directions. For example, ACKs sent by the server measure acknowledgment of client-originated segments—not acknowledgment of server-originated segments.

In a spreadsheet or analysis script, select the same data-transfer phase and calculate the same statistics in each run. Use tcp.analysis.acks_frame to check that the matched segments belong to the intended sample set. Keep frame references so unusual values can be checked against the original trace. Keep exports private too: timing and port metadata can still reveal activity patterns.

If you have captures at both ends

Two simultaneous captures can help localize delay, but subtracting their timestamps introduces a second clock:

Observed transit interval = timestamp at B − timestamp at A

Match the same packet, accounting for retransmitted copies and any header transformations. For TCP, use the connection mapping, raw sequence range (tcp.seq_raw plus segment length), flags and surrounding packets; frame numbers will differ between files. Do not assume relative sequence numbers share the same baseline if the captures started at different times. If offloading makes one captured segment correspond to several wire packets, that is not a simple same-packet subtraction.

To call the result a one-way latency measurement, establish the relative clock offset, drift and timestamp uncertainty. RFC 7679 explains how synchronization error and host-versus-wire timestamp differences affect one-way measurements. Do not align a packet to the same timestamp in both files and then use it as evidence of zero transit delay—that alignment removes the interval you wanted to measure.

Without trustworthy cross-clock timing, compare each capture’s local intervals instead. For a clearly matched transaction, the server-side request-arrival-to-response-departure interval can help distinguish service turnaround from the client-observed wait. That interval still includes endpoint handling; it is not automatically application CPU time.

Likewise, stable ACK RTT alongside slower application responses is a reason to investigate service processing, connection setup or other waits—not proof that the network is healthy. If TLS hides the request boundaries, use authorized application instrumentation rather than guessing from encrypted packet bursts. See what HTTPS hides in a packet capture.

A useful final comparison names the metric, capture point, direction, workload, sample count and spread: “client-observed TCP ACK RTT increased across comparable runs” is supportable where “the network added exactly this much delay” may not be.