Why TCP Retransmissions Stall Industrial Camera Communication, and How to Isolate Them
· Updated: · Go Komura · TCP, Networking, Bug Investigation, Windows Development, Industrial Camera
Revision history (2 updates, last updated Sep 1, 2026)
A log of the changes made to this article. Where a pre-update version was archived, it stays readable at a permanent DOI link.
- Retranslated as a full translation of the Japanese original. The previous English version was an abridgement that carried only part of the source, so sections, tables, Mermaid diagrams, figure captions and FAQ entries were missing. All of them have been restored to match the Japanese original, and the technical claims are the same as in the Japanese version.
- Fixed a display problem where lines containing a vertical bar were rendered as a table, leaving the reference links unclickable. The text itself is unchanged.
- First published
Cite this article(DOI: 10.5281/zenodo.21614466)
This article is archived on Zenodo. Below are both the DOI that always resolves to the latest version and the DOI pinned to the version you are reading.
Go Komura (2026). Why TCP Retransmissions Stall Industrial Camera Communication, and How to Isolate Them. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21614466 https://comcomponent.com/en/blog/2026/03/11/001-tcp-retransmission-rfc1323-industrial-camera/
- DOI (latest version)
- 10.5281/zenodo.21614466
- DOI (this version)
- 10.5281/zenodo.22217125
In communication with industrial cameras and equipment control, the most troublesome symptom is a link that is fast on average but occasionally stalls for several seconds. It rarely reproduces and nothing happens most of the time, so the UI, threads, the GC, the camera SDK, the NIC, and the switch all start to look slightly suspicious.
This article deals with a case where TCP communication between a host and an application controlling an industrial camera occasionally stopped for a few seconds. When we investigated, the culprit was not the application freezing, but TCP waiting on a retransmission caused by packet loss. Furthermore, enabling the RFC1323-family timestamps feature (in the current standards landscape, RFC 7323) allowed us to keep the wait time to a minimum in this system.
Device names, configurations, and numbers have been generalized, but the way of thinking applies directly in practice.
Table of Contents
- The Conclusion First (In One Line)
- How the Symptom Appears
- 2.1. The App Is Alive, but Responses Alone Stall for Seconds
- 2.2. Low Frequency Makes It Hard to See in Logs Alone
- What Was Actually Happening (Diagrams)
- 3.1. Packet Loss Leads into a Retransmission Wait
- 3.2. The Multi-Second Stalls Matched the Shape of RTO
- What We Looked at During the Investigation
- 4.1. First Rule Out In-App Stall Causes
- 4.2. Confirm Retransmissions with a Packet Capture
- 4.3. Look at the Negotiated TCP Options
- Why RFC1323 Timestamps Help
- 5.1. Timestamps Exist for RTTM and PAWS
- 5.2. They Remove the Ambiguity of RTT Measurement on Retransmission
- 5.3. Why We Could Tighten the Wait Time in This Case
- What We Actually Did
- 6.1. Enable Timestamps
- 6.2. Verify TSopt in the SYN / SYN-ACK
- 6.3. Where to Look When It Still Doesn’t Help
- What to Check in Wireshark
- A Rough Decision Guide
- Summary
- References
In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (19 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle
1. The Conclusion First (In One Line)
- TCP communication that occasionally stalls for several seconds can be caused not by the app freezing, but by a retransmission wait following packet loss
- If a packet capture shows
Retransmissionwith a large time gap, and the stall duration matches how RTO waits behave, it is quite suspicious - The TCP timestamps option is a mechanism for RTT measurement and PAWS, and it also removes the ambiguity of RTT measurement on retransmission
- In this case, enabling the RFC1323-family timestamps feature reduced the time the RTO estimate stayed stale and conservative, keeping the multi-second stalls to a minimum
- However, this is not magic that makes the loss itself disappear. Reviewing the physical layer, NIC, switches, intermediate devices, drivers, and buffer design is still needed separately
In short, if the true identity of “it occasionally stalls for a few seconds” is wait time inside TCP, then working hard only on application-level retries misses the mark. It is faster to look at the wire first and confirm whether you are in a retransmission wait.
flowchart TB
accTitle: Flow of this article's conclusion
accDescr: Shows that for TCP communication that occasionally stalls for several seconds you should look at the wire first and confirm whether it is a retransmission wait, that timestamps can sometimes shorten the wait, and that investigating the packet loss itself is still a separate task.
sym["TCP communication that occasionally stalls for seconds"] --> wire["Look at the wire first"]
wire --> conf["Confirm whether this is a retransmission wait"]
conf -.-> ts["Timestamps may shorten the wait"]
conf -.-> loss["Loss source still needs separate investigation"]
Figure 1: Before working hard on application retries, use the wire to pinpoint where the waiting happens.
A stream of TCP acronyms follows from here. For Windows developers whose specialty is not networking, here they are up front. Get these down and nothing later should trip you up.
| Term | Full name | Meaning |
|---|---|---|
| ACK | Acknowledgment | Acknowledgment. The mechanism for telling the peer how much data has been received so far |
| RTT | Round-Trip Time | Round-trip time. The time from sending until the ACK comes back |
| RTO | Retransmission Timeout | The retransmission timer. If no ACK returns within this time, the data is retransmitted. It is computed from the estimated RTT |
| RTTM | Round-Trip Time Measurement | Measurement of RTT. One of the two purposes of the timestamps feature |
| PAWS | Protect Against Wrapped Sequences | Protection against the failure caused by sequence numbers wrapping around. The other purpose of the timestamps feature |
| TSopt | TCP Timestamps Option | One of the options carried in the TCP header. Kind 8, length 10 bytes, carrying the following two values |
| TSval | Timestamp Value | The value of the sender’s own clock, inserted by the sender |
| TSecr | Timestamp Echo Reply | The field that returns the received TSval unchanged. It tells you which transmission an ACK belongs to |
| SACK | Selective Acknowledgment | The mechanism by which the receiver reports individually which ranges it has received |
| Dup ACK | Duplicate ACK | Repeated ACKs pointing at the same sequence number. A sign that something is missing in between |
| fast retransmit | - | The mechanism that retransmits once a certain number of Dup ACKs have accumulated, without waiting for the RTO to expire. The Windows default is after receiving three ACKs for the same sequence number (the first one plus two duplicates) |
| Karn’s algorithm | - | The rule that you must not take an RTT sample from a retransmitted segment, because you cannot tell which transmission the ACK belongs to |
2. How the Symptom Appears
2.1. The App Is Alive, but Responses Alone Stall for Seconds
The first confusing part is that the application as a whole does not look frozen.
- The UI is not completely dead
- The process has not crashed
- The CPU is not pegged
- Yet the responses to camera control commands occasionally drop out for several seconds
Symptoms like this are hard to distinguish from an in-app deadlock or infinite loop. Moreover, in equipment control, a single multi-second stall directly creates the impression of a line stoppage. Even if the averages look clean, the perception on the shop floor is considerably worse.
2.2. Low Frequency Makes It Hard to See in Logs Alone
What makes this type of defect tedious is the low occurrence rate. It behaves like once an hour, once every half day, or only when conditions happen to line up.
If you chase it only through logs, it usually goes like this.
- The application log stops at “sent it” and “no response came back”
- The receiver-side log looks like “nothing arrived”
- Some other event happens to occur in the same time window, scattering the suspects
In situations like this, trying to reconstruct causality from application logs alone is a pretty reliable way to get bogged down. It is faster to step down one layer to the communication level.
flowchart TB
accTitle: Why logs alone do not identify the culprit
accDescr: Shows that the application log stops at sent it but nothing came back, the receiver-side log looks like nothing arrived, and another event in the same time window scatters the suspects, so rather than reconstructing causality from application logs alone it is faster to step down to the communication layer.
l1["App log: sent it but no response"] --> lost["Suspects scatter and the hunt bogs down"]
l2["Receiver log: nothing arrived"] --> lost
l3["Another event in the same window"] -.-> lost
lost --> down["Step down one layer to the communication level"]
Figure 2: Chasing a low-frequency stall through logs alone bogs down. Looking at packets is faster.
3. What Was Actually Happening (Diagrams)
3.1. Packet Loss Leads into a Retransmission Wait
The storyline this time is simple. A packet was lost somewhere along the way, the sender waited for an ACK, none came, so it waited out the RTO and then retransmitted.
sequenceDiagram
participant Host as Host app
participant Net as Network
participant Cam as Camera side
Host->>Net: Control command (Seq=N)
Note over Net: Lost here
Note over Host: No ACK arrives, so it waits
Note over Host: Recovering this request requires waiting out the RTO
Host->>Net: Retransmit the control command
Net->>Cam: Retransmitted packet arrives
Cam-->>Net: ACK
Net-->>Host: ACK
Note over Host: Communication resumes here
Figure 3: When a packet is lost, no ACK comes back, and the sender retransmits only after the RTO expires. To the application, that interval looks like a stall of several seconds.
From the application’s point of view it looks like “it stalled for a few seconds,” but from TCP’s point of view it was simply “no ACK has arrived yet, so I am waiting for the retransmission timer to expire.” It is unglamorous, but this kind of stall happens all the time.
The control traffic in this case consisted mostly of small request/response exchanges, and a single exchange did not have a large amount of unacknowledged data in flight. As a result, this was a configuration where the RTO wait tended to surface before enough duplicate ACKs could accumulate to trigger fast retransmit.
flowchart TB
accTitle: Why the RTO wait surfaces in control traffic
accDescr: Shows that control traffic dominated by small request/response exchanges has little unacknowledged data in flight, so not enough duplicate ACKs accumulate to trigger fast retransmit, and as a result the RTO wait surfaces.
small["Mostly small request/response exchanges"] --> few["Little unacknowledged data in flight"]
few --> nodup["Not enough Dup ACKs accumulate"]
nodup --> nofr["Hard to trigger fast retransmit"]
nofr --> rto["The RTO wait surfaces"]
Figure 4: Unlike traffic carrying large volumes of data, loss in control traffic tends to end up as a wait for the RTO to expire.
3.2. The Multi-Second Stalls Matched the Shape of RTO
TCP’s retransmission wait, while it varies by implementation, behaves conservatively. Under RFC 6298, the initial RTO has a baseline of 1 second; if the computed value is smaller, it is rounded up to 1 second, and when a timeout occurs, the RTO doubles.
flowchart LR
A[Packet loss] --> B[No ACK arrives]
B --> C[Wait out RTO]
C --> D[Retransmit]
D --> E{ACK returned?}
E -- Yes --> F[Communication resumes]
E -- No --> G[Double the RTO]
G --> C
Figure 5: The RTO doubles every time no ACK comes back. The 1-second, 2-second, 4-second pattern of waits comes from this shape.
So even in situations where you want things resolved within a few hundred milliseconds, under bad conditions the waits can look like 1 second, 2 seconds, 4 seconds. The “occasionally stalls for a few seconds” in this case lined up with that shape quite naturally.
4. What We Looked at During the Investigation
4.1. First Rule Out In-App Stall Causes
Rather than jumping straight to blaming TCP, we first ruled out the typical application-side causes.
| What we checked | Why we looked | Conclusion in this case |
|---|---|---|
| UI thread / worker threads | Check for hangs or mutual waits | Not the primary cause |
| CPU usage | Check for processing delays under high load | Not pegged even during the stalls |
| GC / memory pressure | Check for pauses | The shape of the stall durations did not match |
| Camera SDK calls | Check for waits inside the SDK | Did not match the delays on the wire |
| Packet capture | Check for retransmissions at the communication layer | This is where the cause came into view |
The important thing here is to not pick the culprit based on application-log timestamps alone. In equipment control applications, a wait at the upper layer is sometimes just a reflection of a wait at the lower layer.
flowchart TB
accTitle: Isolation order that rules out in-app causes first
accDescr: Shows the isolation order of ruling out typical in-app stall causes such as threads, CPU, GC and the camera SDK before taking a packet capture to check for retransmissions at the communication layer, rather than jumping straight to blaming TCP.
app["Rule out threads, CPU, GC and the SDK first"] --> cap["Look at the communication layer with a packet capture"]
cap --> found["The retransmission storyline comes into view"]
app -.-> warn["Do not pick the culprit from log timestamps alone"]
Figure 6: Do not jump to conclusions. Rule out the typical in-app causes, then go down to the wire.
4.2. Confirm Retransmissions with a Packet Capture
When we took a packet capture, we could see TCP Retransmission in the time window of the stall, and furthermore that no ACK had come back just before it.
These are the points to look at.
- Is the same
Seqbeing retransmitted? - Does the time gap until the retransmission match the stall duration?
- Does it look like an RTO-expiry wait rather than
Dup ACKorFast Retransmission? - Does the problematic connection always show up as the same
tcp.stream?
When these line up, “TCP is waiting on a retransmission” becomes much more likely than “the app is frozen.”
flowchart TB
accTitle: Checks that confirm a retransmission wait
accDescr: Shows that when the same Seq is being retransmitted, the time gap before the retransmission matches the stall duration, and the pattern looks like an RTO expiry wait rather than a fast retransmission, the reading that TCP is waiting on a retransmission rather than the app being frozen becomes much stronger.
c1["Is the same Seq retransmitted?"] --> conc["TCP is waiting on a retransmission"]
c2["Does the gap match the stall duration?"] --> conc
c3["Does it look like an RTO expiry wait?"] --> conc
conc -.-> not["It is not the app that is frozen"]
Figure 7: When these three points line up, TCP waiting on a retransmission becomes far more likely than the app being frozen.
4.3. Look at the Negotiated TCP Options
The next thing we looked at was the SYN / SYN-ACK at connection setup. Timestamps are negotiated in the TCP 3-way handshake, so if TSopt does not appear there, it is not used on that connection.
sequenceDiagram
participant Host as Host
participant Cam as Camera side
Host->>Cam: SYN + TSopt ?
Cam-->>Host: SYN/ACK + TSopt ?
Host->>Cam: ACK
Note over Host,Cam: Only after negotiating here can TSopt be used on subsequent segments
Figure 8: Timestamps are negotiated in the 3-way handshake. If TSopt is absent from the SYN / SYN-ACK, it is not used on that connection.
Fiddling with OS settings without looking at this is another unglamorous way for things to go wrong: “I’m sure I enabled it, but it isn’t taking effect.” The facts on the wire are stronger than the configured values.
5. Why RFC1323 Timestamps Help
In practice people still call this “the RFC1323 timestamps,” but the current standard is RFC 7323. This article follows the customary usage and writes RFC1323, while meaning the TCP timestamps option.
5.1. Timestamps Exist for RTTM and PAWS
TCP’s timestamps option is used mainly for two purposes.
- RTTM (Round-Trip Time Measurement)
- PAWS (Protect Against Wrapped Sequences)
What helped in this case was the RTTM side. By having the peer echo the TSval of a transmitted segment back in the ACK’s TSecr, the sender can measure RTT more finely and more accurately.
flowchart TB
accTitle: The two purposes of the timestamps option
accDescr: Shows that the TCP timestamps option serves two purposes, RTTM which is round-trip time measurement and PAWS which protects against wrapped sequence numbers, and that what helped in this case was the RTTM side.
tso["timestamps option"] --> rttm["RTTM (round-trip time measurement)"]
tso --> paws["PAWS (protection against wrapped sequences)"]
rttm --> hit["This is the side that helped here"]
rttm -.-> how["Measure by echoing TSval back in the ACK TSecr"]
Figure 9: Timestamps serve two purposes, RTTM and PAWS. What helped in this case was the RTT measurement side.
5.2. They Remove the Ambiguity of RTT Measurement on Retransmission
Once a retransmission happens, without timestamps it becomes ambiguous whether “this ACK is for the original transmission or for the retransmission.” This is the point that Karn’s algorithm is concerned with.
RFC 6298 says you must not take an RTT sample from a retransmitted segment. The reason is that you cannot tell which transmission the ACK is for. With the timestamps option, however, this ambiguity goes away: by looking at the TSecr in the arriving ACK, you can identify which segment, with which TSval, actually got through.
sequenceDiagram
participant Host as Sender
participant Cam as Receiver
Host->>Cam: Seq=N, TSval=1000
Note over Host,Cam: This segment is lost
Note over Host: No ACK arrives, so it waits
Host->>Cam: Retransmit Seq=N, TSval=2000
Cam-->>Host: ACK, TSecr=2000
Note over Host: Can tell which transmission this responds to
Figure 10: The TSecr value tells you whether an ACK responds to the original transmission or to the retransmission.
This is the core of the improvement in this case.
5.3. Why We Could Tighten the Wait Time in This Case
In this case, packet loss occurred from time to time, and each occurrence tended to push the RTT / RTO estimates toward the conservative side. Enabling timestamps makes it easier to update the RTT estimate even in scenarios involving retransmissions, which limits how long the RTO estimate keeps inflating while stale.
This is an easy place to skip a step, so let me break it down a little more carefully.
First, the floor on the RTO itself does not change with or without timestamps. RFC 6298 states that a computed RTO below 1 second should be rounded up to 1 second. Implementations may also impose their own floor; on Windows that is MinRtoMs, which shows up in Get-NetTCPSetting (it takes values from 20 to 300 milliseconds in 10-millisecond steps). In other words, adding timestamps did not lower the floor.
What actually helps sits one step earlier. RFC 6298 defines the following three behaviors.
- Every time the retransmission timer expires, double the RTO (exponential backoff)
- A backed-off RTO returns to its normal value once a new RTT measurement becomes available
- That “new RTT measurement” can only be obtained when data that has not been retransmitted is sent and acknowledged
On top of that, Karn’s algorithm forbids taking an RTT sample from a retransmitted segment. This restriction, however, is lifted when the timestamps option is in use. As covered in 5.2, the TSecr value tells you which transmission an ACK belongs to.
Lay all of that out and the storyline becomes clear. In a system where loss keeps occurring sporadically, conditions 2 and 3 are hard to satisfy without timestamps, so the doubled RTO stays in place for a long time before measurements bring it back down. If the next loss arrives while it is in that state, the wait starts at 2 or 4 seconds instead of 1. With timestamps, measurement can resume even across intervals that include retransmissions, so this “time spent unable to recover” gets shorter. That is the path by which it helped here.
flowchart TB
accTitle: Conditions for a doubled RTO to recover and how timestamps help
accDescr: Shows that the RTO doubles on every timeout and returns to its normal value once a new RTT measurement becomes available, that such a measurement can only come from an ACK for data that has not been retransmitted, and that lifting this restriction with timestamps shortens the time a doubled RTO stays unable to recover.
backoff["RTO doubles on every timeout"] --> ret["Returns to normal on a new RTT measurement"]
ret -.-> limit["Measurements come only from ACKs for non-retransmitted data"]
ts2["Timestamps allow measurement across retransmitted intervals"] --> often["More opportunities to re-measure"]
often --> short["Less time with a doubled RTO stuck high"]
Figure 11: The core of the effect is not a lower floor, but a doubled RTO returning to normal sooner because measurements come in.
To be honest about it, this article does not include measured RTO values after the change. What we do know is that multi-second stalls dropped to a level where they stopped being a problem on the shop floor. If you need to show the effect in numbers, the shortest path is to use the display filters from section 7 together with the Time delta from previous displayed packet column and compile the distribution of time gaps before retransmissions, before and after the change.
Put differently, what we did is not magic that makes TCP faster, but reducing the time TCP keeps watching and waiting longer than necessary.
Of course, RFC 7323 does not claim that “more RTT samples cleanly solve everything.” The degree to which it helps RTO optimization is limited in some respects. Still, the fact that it removes the ambiguity on retransmission can help quite naturally in a system like this one.
There are caveats.
- Parts of this depend on the TCP stack implementation
- Timestamps alone do not make the packet loss itself disappear
- If the physical layer or intermediate devices are at fault, the root cause lies elsewhere
- SACK, NIC drivers, offload settings, and switch-side problems are better examined separately
That said, in a system like this one, where loss is not zero but what really hurts is the multi-second wait, it can be quite effective.
6. What We Actually Did
6.1. Enable Timestamps
As the countermeasure, we made sure the timestamps option could be negotiated on both ends of the connection. On Windows systems this is sometimes treated as the RFC 1323 option, and it is affected by OS and network settings.
Here are the concrete steps. First, check the current state.
netsh interface tcp show global
The output contains an entry for RFC 1323 timestamps, so check whether it is enabled there. To enable it, run this from an elevated command prompt.
netsh interface tcp set global timestamps=enabled
The values accepted for timestamps are disabled, enabled, and default, where default restores the system default.
To inspect or set it from PowerShell, use these.
Get-NetTCPSetting | Select-Object SettingName, Timestamps, MinRtoMs, InitialRtoMs
Set-NetTCPSetting -SettingName InternetCustom -Timestamps Enabled
The values accepted for Timestamps are Enabled and Disabled. Which SettingName values you can modify differs by Windows version, so instead of firing off Set- right away, run Get-NetTCPSetting first and confirm which names actually exist. Passing a name that does not exist stops you right there.
On older systems, if you want to inspect the registry directly, the value is Tcp1323Opts (REG_DWORD) under the following key.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
The values mean: 0 disables the RFC 1323 options, 1 enables window scaling only, 2 enables timestamps only, and 3 enables both. It is easier to remember as bit 0 for window scaling and bit 1 for timestamps.
There are three things to watch out for when you change this setting.
- It only takes effect on new connections. Timestamps are negotiated in the 3-way handshake, so existing connections are unaffected. The device-side connection has to be re-established
- It does not work unless both ends support it. Enabling it only on the host does nothing if the camera side does not return TSopt in the SYN/ACK; that connection will not use it
- The setting also changes the character of the connection. Timestamps make the TCP header larger, so slightly less data fits in each segment
In practice, however, what matters is not “it is enabled in the settings screen” but “TSopt is actually present on the SYN / SYN-ACK packets on the wire.” This really is true.
flowchart TB
accTitle: Three cautions when configuring timestamps
accDescr: Shows three cautions about configuring timestamps: because they are negotiated in the 3-way handshake the setting only takes effect on new connections, both ends must support it, and the larger header means slightly less data fits in each segment.
care["Three cautions when configuring"] --> n1["Takes effect only on new connections"]
care --> n2["Both ends must support it"]
care --> n3["Header grows so payload shrinks slightly"]
n1 -.-> re["Re-establish the device-side connection"]
Figure 12: Changing the setting is not the end of it. You still need to re-establish the connection and confirm the peer supports it.
6.2. Verify TSopt in the SYN / SYN-ACK
After enabling it, we verified three things.
- Does the SYN of the connection in question carry TSopt?
- Does the SYN/ACK side return TSopt as well?
- Do subsequent data segments and ACKs continue to carry TSopt?
Only once these are confirmed can you say “timestamps are actually being used on that connection.”
6.3. Where to Look When It Still Doesn’t Help
Even with timestamps enabled, improvement can be sluggish in cases like these.
- The loss rate itself is high
- An intermediate device breaks, drops, or mangles TCP options
- There is a separate problem around the NIC / driver / offloading
- The application hangs everything off a single synchronous call, so one wait looks like a total stall
- The primary cause is actually not TCP, but a processing stall on the camera side or a clogged queue inside the device
So it is clearest to proceed with countermeasures in this order.
- First confirm the retransmission wait on the wire
- Check whether TSopt is negotiated
- Enable timestamps and measure the improvement delta
- If problems remain, tackle the loss source and the application design separately
flowchart TB
accTitle: The order in which to apply countermeasures
accDescr: Shows the order for countermeasures: first confirm the retransmission wait on the wire, then check whether TSopt is negotiated, then enable timestamps and measure the improvement delta, and if problems remain tackle the loss source and the application design separately.
s1["Confirm the retransmission wait on the wire"] --> s2["Check whether TSopt is negotiated"]
s2 --> s3["Enable timestamps and measure the delta"]
s3 --> s4["If it remains, tackle loss source and design separately"]
Figure 13: Working in the order confirm, negotiate, enable, then investigate what is left makes it easier to isolate why it is not helping.
7. What to Check in Wireshark
Here are display filters that are handy for isolation.
tcp.stream eq <target stream>
tcp.analysis.retransmission
tcp.analysis.fast_retransmission
tcp.analysis.lost_segment
tcp.options.timestamp.tsval
tcp.options.timestamp.tsecr
There are a few tricks to reading the results.
- Narrow down to the target connection with
tcp.stream - Display
Time delta from previous displayed packetto see the stalled seconds directly - Confirm whether
Retransmissionappears at the problematic moment - Confirm whether TSopt is negotiated in the SYN / SYN-ACK at connection setup
- Check whether
TSecris being returned in the ACKs
It is worth spelling out in words what the screen looks like, too. Once you are used to it, this case is recognizable at a glance.
| Where to look | What you see |
|---|---|
| Info column in the packet list | Retransmitted packets are tagged [TCP Retransmission] |
| Row color | It falls under Wireshark’s default “Bad TCP” coloring rule, so that row alone turns red text on a black background. You can catch it even while skimming |
| Details pane | Select the row, expand Transmission Control Protocol, and open SEQ/ACK analysis inside it to see the note that the packet was judged a retransmission |
| Time delta | Add Time delta from previous displayed packet as a column and you can read how many seconds elapsed since the previous displayed packet. This is where 1 second, 2 seconds line up |
| Options on the SYN | Select the SYN row, expand Options, and the presence or absence of a Timestamps entry tells you whether TSopt is there |
The typical pattern goes like this. A row with the same Seq appears again one second later, then once more two seconds after that, an ACK comes back right after the last one, and normal exchanges resume from there. If those “blank seconds” match the period during which the application log shows responses stalled, the culprit is all but confirmed.
When correlating logs with packets, also watch out for the offset between application clock and capture clock. If they are skewed, you tend to pin the blame on an unrelated event.
flowchart TB
accTitle: Flow for confirming the culprit in Wireshark
accDescr: Shows the flow of narrowing down to the target connection with tcp.stream, reading the stalled seconds directly from the time delta column, and confirming the culprit when those blank seconds match the period during which the application log shows responses stalled.
filt["Narrow to the target connection with tcp.stream"] --> delta["Read the blank seconds in the time delta column"]
delta --> re["Confirm retransmissions of the same Seq lining up"]
re --> match{"Matches the app stall duration?"}
match -->|"Yes"| fix["Culprit all but confirmed"]
match -->|"No"| other["Suspect clock offset or another cause"]
Figure 14: Filter, read the time deltas, correlate. These three moves pin down what the blank seconds really are.
8. A Rough Decision Guide
| Symptom | First suspect | First action |
|---|---|---|
| Occasionally stalls for several seconds | TCP’s RTO wait | Confirm retransmissions and time gaps in packets |
| Stalls at almost the same timing every time | In-app waits, device-side processing, fixed timeouts | Look at threads, SDK calls, device logs |
| Only degrades under high load | CPU, GC, clogged queues | Look at CPU, interrupts, memory, queue lengths |
| Bad across a wide range of connections at once | Physical layer, switches, intermediate devices | Look at NIC, cables, port statistics, intermediate device logs |
| Changed settings but nothing changed | TCP option is not being negotiated | Re-check the SYN / SYN-ACK |
That last row is genuinely common. The satisfaction of having tweaked a setting and the fact of it being used on the wire are two different things.
9. Summary
Key points this time:
- “Occasionally stalls for several seconds” can be TCP’s retransmission wait, not the app freezing
- If the stall duration matches how RTO waits behave and
Retransmissionis visible, that is a strong lead - The TCP timestamps option is a mechanism for RTTM and PAWS, and it removes the ambiguity of RTT measurement on retransmission
- In this case, enabling the RFC1323-family timestamps limited the time the RTO stayed excessively conservative
Approaches to avoid:
- Picking the culprit for a communication stall from application logs alone
- Looking only at OS settings without looking at actual packets
- Assuming that enabling timestamps will also eliminate the cause of the loss
Approaches that work in practice:
- Look at the wire first
- Confirm the shape of the retransmissions and wait times
- Confirm the TSopt negotiation
- Even after the improvement, tackle the loss source and the application design separately
In other words, with this class of defect, “pinpointing where it is waiting” comes before “making it faster.” Just by not missing that, the investigation gets considerably shorter.
10. References
- RFC 1323 - TCP Extensions for High Performance
- RFC 7323 - TCP Extensions for High Performance
- RFC 5681 - TCP Congestion Control
- RFC 6298 - Computing TCP’s Retransmission Timer
- Description of Windows TCP features - Windows Server | Microsoft Learn
- Netsh commands for Interface Transmission Control Protocol - Microsoft Learn
- Set-NetTCPSetting - Microsoft Learn
- Get-NetTCPSetting - Microsoft Learn
- Wireshark User’s Guide - Time Display Formats And Time References
- Wireshark User’s Guide - Packet Colorization
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Pitfalls of Network Drives and UNC Paths — Working With File Servers (Shared Folders) From a Business Application
This article organizes the classic problems that show up when a business application writes to or watches a shared folder: why a drive le...
Building a Windows Failure-Path Test Foundation with Application Verifier
What Application Verifier is, organized together with how to build a Windows failure-path test foundation using Handles, Heaps, Low Resou...
Investigating Long-Run Crashes of an Industrial Camera App - The Handle Leak (Part 1)
How to look at a Windows app that suddenly crashes after long-running operation, using a case study of an industrial camera control app, ...
The Network Works but Windows Says "No internet" — Isolating NCSI, DNS, Proxy, and VPN on Windows
Why Windows says "No internet" while the network works, starting from the NCSI verdict. Isolate DNS, proxy, VPN, and captive portals with...
The Order of Name Resolution on Windows — hosts, the DNS Cache, LLMNR/mDNS, and DoH
Whether hosts, the DNS cache, the DNS server, or LLMNR/mDNS answered decides why some PCs fail. Learn the Windows name resolution order, ...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Bug Investigation & Long-Run Failures
Topic page for intermittent failures, communication diagnosis, long-run crashes, and failure-path test foundations.
Related Case Study
This case-study page shows a similar structure for diagnosis, prioritization, or redesign.
How We Isolated Multi-Second Communication Stalls
Case-study page for separating a rare communication stall into retransmission wait behavior and OS-side conditions.
Where This Topic Connects
This article connects naturally to the following service pages.
Bug Investigation & Root Cause Analysis
This article is about isolating a hard-to-reproduce communication stall using packets and evidence, which is exactly what our bug investigation and root-cause analysis service covers.
Windows App Development
It also connects to consultations on reviewing communication design and monitoring from the implementation side, for Windows applications that integrate with equipment.
Frequently Asked Questions
Common questions about the topic of this article.
- What is a TCP Retransmission?
- It is the mechanism by which TCP sends the same data again when no ACK (acknowledgment) comes back for a packet it transmitted. If a packet is dropped somewhere along the path, the sender waits for the ACK, and when none arrives it waits for the retransmission timer (RTO) to expire before resending. From the application's point of view this looks like a stall of several seconds, but from TCP's point of view it is simply that no ACK has arrived yet, so it was waiting for the retransmission timer to expire - a perfectly ordinary way for traffic to stall. In a packet capture you can observe it as a TCP Retransmission.
- What causes TCP Retransmissions?
- The immediate trigger is packet loss: no ACK comes back, so a retransmission happens. As for where the loss originates, you need to examine the physical layer (cables and ports), the NIC along with its driver and offload settings, and problems in switches or intermediate devices, each on its own. Note that while enabling TCP timestamps and similar measures can shorten the wait after a retransmission, they are not magic that makes the loss itself disappear, so investigating the loss source remains a separate task. There are also cases where an intermediate device mangles or strips TCP options, and cases where the primary cause is not TCP at all but a processing stall on the device side.
- Why does a TCP retransmission stall communication for several seconds?
- Because TCP's retransmission timer (RTO) waits conservatively. Under RFC 6298 the initial RTO has a baseline of 1 second, a computed value smaller than that is rounded up to 1 second, and the RTO doubles on every timeout. Under bad conditions that produces waits of 1 second, then 2 seconds, then 4 seconds. In control traffic dominated by small request/response exchanges, the RTO wait tends to surface before enough duplicate ACKs accumulate to trigger fast retransmit, which shows up as a rare stall of several seconds. Enabling the TCP timestamps option can, in some cases, remove the ambiguity of RTT measurement on retransmission and limit how long the RTO estimate stays excessively conservative.
- How do I investigate TCP Retransmissions in Wireshark?
- You can use display filters such as tcp.analysis.retransmission, tcp.analysis.fast_retransmission, and tcp.analysis.lost_segment. Narrow down to the connection in question with tcp.stream, display Time delta from previous displayed packet to read the stalled seconds directly, then check whether a Retransmission appears at the moment of the problem and whether the time gap before the retransmission matches the stall duration. To see whether TCP timestamps are in use, check whether TSopt was negotiated in the SYN / SYN-ACK at connection setup. The fact that TSopt is present on the actual packets matters more than a settings screen showing the feature as enabled.