TCP Retransmission שעוצר תקשורת עם מצלמה תעשייתית — איך מפרקים את זה
· עודכן בתאריך: · Go Komura · TCP, רשתות, חקירת תקלות, פיתוח Windows, מצלמה תעשייתית
היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 11 Mar 2026)
- פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22173343)
מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.
Go Komura (2026). TCP Retransmission שעוצר תקשורת עם מצלמה תעשייתית — איך מפרקים את זה. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22173343 https://comcomponent.com/he/blog/tcp-retransmission-rfc1323-industrial-camera/
- DOI (הגרסה האחרונה)
- 10.5281/zenodo.22173343
- DOI (הגרסה הזו)
- 10.5281/zenodo.22173344
בתקשורת של מצלמות תעשייתיות ובקרת התקנים, התופעה הכי מעצבנת היא כשבממוצע הכול מהיר, אבל לפעמים התקשורת נתקעת לכמה שניות. שיעור השחזור נמוך, וברוב הזמן לא קורה כלום — אז UI, threads, GC, ה-SDK של המצלמה, ה-NIC וה-switch כולם מתחילים להיראות קצת חשודים.
המקרה כאן: TCP בין אפליקציה ששולטת במצלמה תעשייתית לבין ה-host, שבו לעיתים רחוקות התקשורת נעצרת לכמה שניות בלבד. בבדיקה התברר שהאשם לא היה stall של האפליקציה, אלא המתנה ל-TCP retransmission אחרי packet loss. בנוסף, הפעלת timestamps לפי RFC1323 (בסיווג הנוכחי RFC 7323) אפשרה במערכת הזו לצמצם את זמן ההמתנה למינימום.
שמות התקנים, תצורה ומספרים הוכללו, אבל אופן החשיבה ישים ישירות בעבודה בפועל.
תוכן עניינים
- השורה התחתונה
- איך הסימפטום נראה
- 2.1. האפליקציה חיה, אבל התגובה נעצרת לכמה שניות
- 2.2. בתדירות נמוכה, קשה לראות את זה רק מהלוגים
- מה באמת קרה (בתרשימים)
- 3.1. מ-packet loss להמתנה ל-retransmission
- 3.2. ה-stall בסדר גודל של שניות תאם את צורת ה-RTO
- מה בדקנו בחקירה
- 4.1. קודם שוללים גורמי stall בתוך האפליקציה
- 4.2. מאמתים retransmission ב-packet capture
- 4.3. בודקים אילו TCP options סוכמו
- למה timestamps של RFC1323 עוזרים
- 5.1. timestamps מיועדים ל-RTTM ול-PAWS
- 5.2. אפשר להסיר את העמימות במדידת RTT בזמן retransmission
- 5.3. למה במקרה הזה התקצר זמן ההמתנה
- מה עשינו בפועל
- 6.1. הפעלת timestamps
- 6.2. בדיקת TSopt ב-SYN / SYN-ACK
- 6.3. איפה לבדוק כשזה עדיין לא עוזר
- נקודות בדיקה ב-Wireshark
- איך לבחור כיוון, בגדול
- סיכום
- מקורות
ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 19, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle
1. השורה התחתונה
- תקשורת TCP שנעצרת לעיתים רחוקות לכמה שניות עשויה להיות לא stall של האפליקציה, אלא המתנה ל-retransmission אחרי packet loss
- אם ב-packet capture רואים
Retransmissionופער זמן גדול, ומשך ה-stall תואם את אופן ההמתנה של ה-RTO — זה חשוד מאוד - TCP timestamps option קיימת למדידת RTT ול-PAWS, והיא גם מאפשרת להסיר את העמימות במדידת RTT בזמן retransmission
- במקרה הזה, הפעלת timestamps לפי RFC1323 קיצרה את הזמן שבו הערכת ה-RTO נשארת ישנה ושמרנית מדי, וכך צומצם ה-stall בסדר גודל של שניות למינימום
- עם זאת, זו לא קסם שמעלים את ה-loss עצמו. השכבה הפיזית, NIC, switch, ציוד ביניים, דרייברים ותכנון buffer נבדקים בנפרד
בקיצור: אם הזהות האמיתית של “לפעמים נתקע לכמה שניות” היא זמן המתנה בתוך TCP, מאמץ שמושקע רק ב-retry באפליקציה מפספס את הליבה. מהיר יותר להסתכל קודם על ה-wire ולקבוע אם זו המתנה ל-retransmission.
flowchart TB
accTitle: זרימת המסקנה במאמר
accDescr: בתקשורת TCP שנעצרת לעיתים רחוקות לכמה שניות מסתכלים קודם על ה-wire וקובעים אם זו המתנה ל-retransmission. אם כן, לפעמים אפשר לקצר את ההמתנה עם timestamps, אבל חקירת מקור ה-packet loss נשארת נפרדת.
sym["תקשורת TCP שנעצרת מדי פעם"] --> wire["קודם מסתכלים על ה-wire"]
wire --> conf["קובעים אם זו המתנה ל-retransmission"]
conf -.-> ts["timestamps עשויות לקצר המתנה"]
conf -.-> loss["חקירת מקור ה-loss נשארת נפרדת"]
איור 1: לפני שמשקיעים ב-retry באפליקציה, קודם קובעים ב-wire איפה ממתינים.
בהמשך יופיעו קיצורי TCP ברצף. למפתחי Windows שרשתות אינן ההתמחות שלהם, הנה סיכום מראש. אם מחזיקים רק את זה, לא נתקעים בהמשך.
| מונח | שם מלא | משמעות |
|---|---|---|
| ACK | Acknowledgment | אישור קבלה. מודיע לצד השני “קיבלתי עד כאן” |
| RTT | Round-Trip Time | זמן הלוך-ושוב. מהשליחה עד שחוזר ה-ACK |
| RTO | Retransmission Timeout | טיימר ה-retransmission. אם ה-ACK לא חוזר בתוך הזמן הזה, יש retransmission. מחושב מהערכת ה-RTT |
| RTTM | Round-Trip Time Measurement | מדידת RTT. אחת ממטרות timestamps |
| PAWS | Protect Against Wrapped Sequences | הגנה מפני wrap של sequence number. המטרה השנייה של timestamps |
| TSopt | TCP Timestamps Option | אחת ה-options בכותרת TCP. סוג 8, אורך 10 בתים, ונושאת שני ערכים |
| TSval | Timestamp Value | הערך שהצד השולח מכניס — השעון שלו |
| TSecr | Timestamp Echo Reply | השדה שמחזיר בדיוק את ה-TSval שהתקבל. כך יודעים לאיזו שליחה שייך ה-ACK |
| SACK | Selective Acknowledgment | המקבל מודיע באופן פרטני אילו טווחים התקבלו |
| Dup ACK | Duplicate ACK | כמה ACK שמצביעים על אותו sequence number. סימן שיש פער באמצע |
| fast retransmit | — | retransmission בלי לחכות ש-RTO יפוג, ברגע שמצטבר מספר מסוים של Dup ACK. ברירת המחדל ב-Windows: אחרי שלושה ACK לאותו sequence number (הראשון ועוד שניים כפולים) |
| האלגוריתם של Karn | — | הכלל שאסור לקחת מדגם RTT מ-segment שעבר retransmission, כי לא יודעים לאיזו שליחה שייך ה-ACK |
2. איך הסימפטום נראה
2.1. האפליקציה חיה, אבל התגובה נעצרת לכמה שניות
מה שמבלבל בהתחלה: האפליקציה כולה לא נראית תקועה.
- ה-UI לא מת לגמרי
- ה-process לא קרס
- גם ה-CPU לא תקוע
- אבל רק התגובה לפקודות בקרת המצלמה נעלמת מדי פעם לכמה שניות
קשה להבחין בין סימפטום כזה לבין deadlock או לולאה אינסופית בתוך האפליקציה. ובבקרת התקנים, stall בודד של כמה שניות מתקבל מיד כרושם של עצירת קו. גם אם הממוצע נראה נקי, החוויה בשטח גרועה למדי.
2.2. בתדירות נמוכה, קשה לראות את זה רק מהלוגים
מה שמקשה בסוג כזה של תקלה הוא התדירות הנמוכה. ההתנהגות היא בערך פעם בשעה, פעם בחצי יום, או רק כשכמה תנאים נפגשים יחד.
אם עוקבים רק דרך לוגים, בדרך כלל קורה כך:
- בלוג האפליקציה זה נעצר על “נשלח” ואז “לא חוזר”
- בצד המקבל הלוג נראה כאילו “שום דבר לא הגיע”
- באותו חלון זמן קורים במקרה גם אירועים אחרים, והחשוד מתפזר
במצב כזה, ניסיון לשחזר סיבתיות רק מלוגי האפליקציה נוטה להסתבך. מהיר יותר לרדת שלב אחד לשכבת התקשורת.
flowchart TB
accTitle: למה לוגים לבדם לא קובעים את החשוד
accDescr: לוג האפליקציה נעצר על נשלח ולא חוזר, לוג הצד המקבל נראה כאילו לא הגיע דבר, ואירועים אחרים באותו חלון זמן מפזרים את החשוד. לכן עדיף לרדת לשכבת התקשורת ולא לנסות לשחזר סיבתיות רק מלוגי האפליקציה.
l1["לוג האפליקציה: נשלח ולא חוזר"] --> lost["החשוד מתפזר ומסתבכים"]
l2["לוג הצד המקבל: לא הגיע דבר"] --> lost
l3["אירוע אחר באותו חלון זמן"] -.-> lost
lost --> down["יורדים שלב לשכבת התקשורת"]
איור 2: stall בתדירות נמוכה שעוקבים אחריו רק בלוגים מסתבך. מהיר יותר להסתכל דרך packets.
3. מה באמת קרה (בתרשימים)
3.1. מ-packet loss להמתנה ל-retransmission
התרחיש הפעם פשוט. packet נפל איפשהו בדרך, הצד השולח המתין ל-ACK, וכשזה לא הגיע הוא חיכה ש-RTO יפוג ואז ביצע retransmission.
sequenceDiagram
accTitle: ממעבר packet loss להמתנה ל-retransmission
accDescr: פקודת בקרה נשלחת מה-host, ה-packet אובד ברשת, ה-host ממתין ש-RTO יפוג, מבצע retransmission, וה-packet המשודר מחדש מגיע למצלמה ומקבל ACK שמסמן חידוש התקשורת.
participant Host as אפליקציית ה-Host
participant Net as הרשת
participant Cam as צד המצלמה
Host->>Net: פקודת בקרה (Seq=N)
Note over Net: כאן קורה ה-loss
Note over Host: ה-ACK לא מגיע, ולכן ממתינים
Note over Host: השחזור של הבקשה הזו כולל המתנה ל-RTO
Host->>Net: retransmission של פקודת הבקרה
Net->>Cam: ה-packet המשודר מחדש מגיע
Cam-->>Net: ACK
Net-->>Host: ACK
Note over Host: כאן התקשורת מתחדשת
איור 3: כש-packet נופל, ה-ACK לא חוזר וממתינים ש-RTO יפוג לפני retransmission. מהאפליקציה, פרק הזמן הזה נראה כ”עצירה של כמה שניות”.
מהאפליקציה זה נראה כ”עצירה של כמה שניות”, אבל מבחינת TCP זה פשוט “ה-ACK עדיין לא הגיע, ולכן ממתינים שטיימר ה-retransmission יפוג”. זה לא מרשים, אבל צורת stall כזו שכיחה למדי.
תקשורת הבקרה במקרה הזה כללה בעיקר request/response קטנים, ובכל חילופין לא נשלחה כמות גדולה של נתונים בלי ACK. לכן במקום שיצטברו מספיק Duplicate ACK כדי להיכנס ל-fast retransmit, המבנה נטה לחשוף קודם המתנה ל-RTO.
flowchart TB
accTitle: למה בתקשורת בקרה נחשפת בקלות המתנה ל-RTO
accDescr: בתקשורת בקרה שמבוססת בעיקר על request/response קטנים יש מעט נתונים בלי ACK, לכן Duplicate ACK לא מצטברים מספיק, קשה להיכנס ל-fast retransmit, ונחשפת המתנה ל-RTO.
small["בעיקר request/response קטנים"] --> few["מעט נתונים בלי ACK"]
few --> nodup["Dup ACK לא מצטברים מספיק"]
nodup --> nofr["קשה להיכנס ל-fast retransmit"]
nofr --> rto["נחשפת המתנה ל-RTO"]
איור 4: בשונה מתקשורת שזורמים בה הרבה נתונים, loss בתקשורת בקרה נוטה להסתיים בהמתנה ש-RTO יפוג.
3.2. ה-stall בסדר גודל של שניות תאם את צורת ה-RTO
ההמתנה ל-TCP retransmission שמרנית באופייה, גם אם יש הבדלים בין מימושים. לפי RFC 6298, ה-RTO ההתחלתי מבוסס על שנייה אחת: אם תוצאת החישוב קטנה מזה, מעגלים כלפי מעלה ל-1 שנייה, וכל timeout מכפיל אותו.
flowchart LR
accTitle: מחזור ההכפלה של RTO עד לחידוש התקשורת
accDescr: packet loss גורם להיעדר ACK, שמוביל להמתנה ל-RTO ואז ל-retransmission. אם ה-ACK חוזר התקשורת מתחדשת, ואם לא, ה-RTO מוכפל והמחזור חוזר על עצמו.
A["packet loss"] --> B["ה-ACK לא מגיע"]
B --> C["המתנה ל-RTO"]
C --> D["retransmission"]
D --> E{"ה-ACK חוזר?"}
E -- "כן" --> F["התקשורת מתחדשת"]
E -- "לא" --> G["הכפלת ה-RTO"]
G --> C
איור 5: ה-RTO מוכפל בכל פעם שה-ACK לא חוזר. צורת ההמתנה של שנייה, שתי שניות, ארבע שניות נובעת מהמנגנון הזה.
לכן, גם ברגעים שבהם היינו רוצים שהעניין ייגמר תוך מאות מילישניות, בתנאים גרועים אפשר לראות דפוס המתנה כמו שנייה, שתי שניות, ארבע שניות. ה”עצירה הנדירה של כמה שניות” במקרה הזה תאמה את הצורה הזו בצורה די ישירה.
4. מה בדקנו בחקירה
4.1. קודם שוללים גורמי stall בתוך האפליקציה
בלי לקבוע מראש ש-TCP הוא האשם, קודם שללנו את הגורמים האופייניים בצד האפליקציה.
| מה נבדק | למה בדקנו | המסקנה במקרה הזה |
|---|---|---|
| UI thread / worker threads | בדיקת hang או המתנה הדדית | לא היה הגורם העיקרי |
| ניצול CPU | בדיקת עיכוב עיבוד בגלל עומס גבוה | גם בזמן ה-stall ה-CPU לא היה תקוע |
| GC / לחץ זיכרון | בדיקת השהיה זמנית | צורת זמן ההשהיה לא תאמה |
| קריאות ל-SDK של המצלמה | בדיקת המתנה בתוך ה-SDK | לא תאם לעיכוב שנצפה ב-wire |
| packet capture | בדיקת retransmission בשכבת התקשורת | כאן נראה חוט הסיבה האמיתי |
החשוב כאן: לא לקבוע את החשוד רק לפי זמני לוג האפליקציה. באפליקציות בקרת התקנים, המתנה בשכבה עליונה לפעמים רק משקפת המתנה בשכבה נמוכה יותר.
flowchart TB
accTitle: סדר הפירוק ששולל קודם גורמים בתוך האפליקציה
accDescr: במקום לקבוע מראש ש-TCP הוא האשם, קודם שוללים גורמי stall אופייניים בתוך האפליקציה כמו threads, CPU, GC ו-SDK של המצלמה, ורק אז בודקים retransmission בשכבת התקשורת באמצעות packet capture.
app["שוללים קודם threads, CPU, GC ו-SDK"] --> cap["בודקים את שכבת התקשורת ב-packet capture"]
cap --> found["מתגלה חוט הסיבה של ה-retransmission"]
app -.-> warn["לא לקבוע חשוד רק לפי זמני הלוג"]
איור 6: לא קובעים מראש. קודם שוללים גורמים אופייניים בתוך האפליקציה, ורק אז יורדים אל ה-wire.
4.2. מאמתים retransmission ב-packet capture
כשלכדנו את ה-packets, ראינו TCP Retransmission בדיוק בחלון הזמן של ה-stall, ומצאנו שממש לפני כן ה-ACK לא חזר.
אלה הנקודות שכדאי לבדוק:
- האם מופיע retransmission לאותו
Seq - האם פער הזמן עד ה-retransmission תואם את משך ה-stall
- האם זה נראה כהמתנה ש-RTO יפוג, ולא כ-
Dup ACKאוFast Retransmission - האם החיבור הבעייתי מופיע תמיד באותו
tcp.stream
כשהנקודות האלה מתיישרות, ההשערה ש”TCP ממתין ל-retransmission” — ולא ש”האפליקציה נעצרת” — מתחזקת מאוד.
flowchart TB
accTitle: נקודות הבדיקה שקובעות המתנה ל-retransmission
accDescr: שלוש נקודות — retransmission לאותו Seq, פער זמן שתואם את משך ה-stall, והופעה שנראית כהמתנה ש-RTO יפוג ולא כ-fast retransmission — כשמתיישרות מחזקות את ההשערה ש-TCP ממתין ל-retransmission ולא שהאפליקציה נעצרת.
c1["retransmission לאותו Seq"] --> conc["TCP ממתין ל-retransmission"]
c2["פער זמן שתואם את משך ה-stall"] --> conc
c3["נראה כהמתנה ש-RTO יפוג"] --> conc
conc -.-> not["האפליקציה לא נעצרת"]
איור 7: אם שלוש הנקודות האלה מתיישרות, ההשערה עוברת מ”האפליקציה נעצרת” ל”TCP ממתין ל-retransmission”.
4.3. בודקים אילו TCP options סוכמו
הדבר הבא שבדקנו היה ה-SYN / SYN-ACK בתחילת החיבור. timestamps מסוכמים ב-3-way handshake של חיבור TCP, ואם TSopt לא מופיע שם, הוא לא ישמש באותו חיבור.
sequenceDiagram
accTitle: משא ומתן על TSopt ב-3-way handshake
accDescr: ה-host שולח SYN עם TSopt אפשרי, המצלמה מחזירה SYN/ACK עם TSopt אפשרי, ורק אחרי שהמשא ומתן מצליח אפשר להשתמש ב-TSopt ב-segments הבאים.
participant Host as ה-host
participant Cam as צד המצלמה
Host->>Cam: SYN + TSopt?
Cam-->>Host: SYN/ACK + TSopt?
Host->>Cam: ACK
Note over Host,Cam: רק אחרי שהמשא ומתן הזה מצליח, אפשר להשתמש ב-TSopt ב-segments הבאים
איור 8: timestamps מסוכמים ב-3-way handshake. אם אין TSopt ב-SYN / SYN-ACK, הם לא ישמשו באותו חיבור.
אם משנים רק את הגדרות מערכת ההפעלה בלי לבדוק את זה, קורה תקלה שקטה נוספת: “הפעלתי, אבל זה לא עובד”. העובדה שנראית ב-wire חזקה יותר מערך ההגדרה.
5. למה timestamps של RFC1323 עוזרים
בפועל השם “timestamps של RFC1323” עדיין נפוץ, אבל הסיווג העדכני הוא RFC 7323. במאמר הזה כותבים RFC1323 לפי המקובל, אך הכוונה היא ל-TCP timestamps option.
5.1. timestamps מיועדים ל-RTTM ול-PAWS
TCP timestamps option משמשת בעיקר לשתי מטרות:
- RTTM (Round-Trip Time Measurement)
- PAWS (Protect Against Wrapped Sequences)
מה שעזר במקרה הזה הוא צד ה-RTTM. הצד השני מחזיר את ה-TSval של ה-segment שנשלח בתוך TSecr של ה-ACK, וכך הצד השולח יכול למדוד את ה-RTT בפירוט ובדיוק רבים יותר.
flowchart TB
accTitle: שתי המטרות של timestamps option
accDescr: TCP timestamps option משמשת לשתי מטרות, RTTM שהיא מדידת round-trip time ו-PAWS שהיא הגנה מפני wrap של sequence number, ובמקרה הזה מה שעזר היה צד ה-RTTM.
tso["timestamps option"] --> rttm["RTTM (מדידת round-trip time)"]
tso --> paws["PAWS (הגנה מפני wrap של sequence number)"]
rttm --> hit["זה מה שעזר במקרה הזה"]
rttm -.-> how["מדידה בהחזרת TSval בתוך TSecr"]
איור 9: למטרת timestamps שני צדדים — RTTM ו-PAWS. במקרה הזה מה שעזר היה צד מדידת ה-RTT.
5.2. אפשר להסיר את העמימות במדידת RTT בזמן retransmission
כשנכנס retransmission, בלי timestamps נוצרת עמימות: “האם ה-ACK הזה שייך לשליחה הראשונה או ל-retransmission?” זו בדיוק הנקודה שהאלגוריתם של Karn מתייחס אליה.
לפי RFC 6298, אסור לקחת מדגם RTT מ-segment שעבר retransmission, כי לא יודעים לאיזו שליחה שייך ה-ACK. אבל כשיש timestamps option, אפשר להסיר את העמימות הזו: הסתכלות על TSecr שמגיע בתוך ה-ACK מאפשרת לזהות איזה segment, עם איזה TSval, הגיע.
sequenceDiagram
accTitle: זיהוי השליחה שאליה שייך ה-ACK באמצעות TSecr
accDescr: segment עם TSval=1000 אובד, השולח ממתין ל-ACK, מבצע retransmission עם TSval=2000, ומקבל ACK עם TSecr=2000 שמאפשר לזהות בוודאות לאיזו שליחה הוא שייך.
participant Host as הצד השולח
participant Cam as הצד המקבל
Host->>Cam: Seq=N, TSval=1000
Note over Host,Cam: ה-segment הזה אובד
Note over Host: ה-ACK לא מגיע, ולכן ממתינים
Host->>Cam: retransmission עם Seq=N, TSval=2000
Cam-->>Host: ACK, TSecr=2000
Note over Host: אפשר לזהות לאיזו שליחה זו התגובה
איור 10: הסתכלות על TSecr מאפשרת לזהות אם ה-ACK הוא תגובה לשליחה הראשונה או ל-retransmission.
זה הליבה של השיפור במקרה הזה.
5.3. למה במקרה הזה התקצר זמן ההמתנה
במקרה הזה packet loss התרחש מדי פעם, ובכל פעם הערכות RTT/RTO נטו להיות שמרניות. הפעלת timestamps מקלה על עדכון הערכת ה-RTT גם ברגעים שכוללים retransmission, וכך מתקצר הזמן שבו הערכת ה-RTO ממשיכה להתנפח בלי עדכון.
זו נקודה שקל לדלג עליה בקפיצה, אז נפרק אותה בזהירות.
קודם כול, הגבול התחתון של ה-RTO עצמו לא משתנה לפי קיום או היעדר timestamps. RFC 6298 קובע שאם ה-RTO המחושב קטן משנייה, יש לעגל אותו כלפי מעלה לשנייה. יש מימושים עם גבול תחתון משלהם — ב-Windows זהו MinRtoMs שמופיע ב-Get-NetTCPSetting (בטווח 20 עד 300 מילישניות, בקפיצות של 10 מילישניות). כלומר, זה לא ש”הגבול התחתון ירד כי הוספנו timestamps”.
מה שבאמת עוזר קורה שלב לפני כן. RFC 6298 קובע שלושה דברים:
- בכל פעם שטיימר ה-retransmission פוקע, ה-RTO מוכפל (exponential backoff)
- ה-RTO שהוכפל חוזר לערכו כשמתקבלת מדידת RTT חדשה
- אותה “מדידת RTT חדשה” מתקבלת רק כשנתונים שלא עברו retransmission נשלחו וקיבלו ACK
יתרה מכך, לפי האלגוריתם של Karn, אסור לקחת מדגם RTT מ-segment שעבר retransmission. אבל כשמשתמשים ב-timestamps option, המגבלה הזו יורדת, כי כמו שהוסבר בסעיף 5.2, הסתכלות על TSecr מאפשרת לזהות לאיזו שליחה שייך ה-ACK.
כשמסדרים את זה ברצף, החוט מתגלה. במערכת שבה loss מתרחש מדי פעם, בלי timestamps קשה שהתנאים 2 ו-3 יתקיימו יחד, ולכן נשאר זמן ארוך שבו ה-RTO המוכפל לא חוזר לערכו על בסיס מדידה בפועל. אם באותו מצב מגיע loss נוסף, ההמתנה מתחילה לא משנייה אלא משתי שניות או ארבע שניות. כשיש timestamps, אפשר למדוד מחדש גם ב-segments שכוללים retransmission, כך שה”זמן שבו לא חוזרים לערך” מתקצר — וזה בדיוק המסלול שעבד במקרה הזה.
flowchart TB
accTitle: התנאים לחזרת ה-RTO המוכפל ואופן הפעולה של timestamps
accDescr: בכל timeout ה-RTO מוכפל וחוזר לערכו כשמתקבלת מדידת RTT חדשה, אבל המדידה מתקבלת רק מ-ACK על נתונים שלא עברו retransmission. כש-timestamps מורידות את המגבלה הזו וניתן למדוד גם ב-segments של retransmission, מתקצר הזמן שבו ה-RTO המוכפל לא חוזר לערכו.
backoff["הכפלת ה-RTO בכל timeout"] --> ret["חזרה לערך עם מדידת RTT חדשה"]
ret -.-> limit["המדידה רק מ-ACK על נתונים שלא עברו retransmission"]
ts2["timestamps מאפשרות מדידה גם ב-retransmission"] --> often["יותר הזדמנויות למדידה מחדש"]
often --> short["מתקצר הזמן שבו ה-RTO המוכפל לא חוזר"]
איור 11: הליבה של אופן הפעולה היא לא ירידה של הגבול התחתון, אלא חזרה מהירה יותר של ה-RTO המוכפל על סמך מדידה בפועל.
בכנות: במאמר הזה לא נאספו ערכי RTO בפועל אחרי השיפור. מה שידוע הוא שהעצירות בסדר גודל של שניות ירדו לרמה שלא מהווה בעיה בשטח. אם רוצים להראות את האפקט במספרים, הדרך הקצרה ביותר היא להשתמש ב-display filters מפרק 7 ובעמודה Time delta from previous displayed packet כדי לרכז את התפלגות פערי הזמן עד ל-retransmission, לפני ואחרי.
במילים אחרות, מה שנעשה כאן אינו קסם שמאיץ את TCP, אלא צמצום הזמן שבו TCP ממשיך “לחכות ולראות” יותר מהנדרש.
כמובן, גם RFC 7323 לא טוען ש”יותר מדגמי RTT פותרים הכול בצורה נקייה”. יש היבטים שבהם התרומה לאופטימיזציה של ה-RTO מוגבלת. אבל היכולת להסיר את העמימות בזמן retransmission היא נקודה שיכולה לעבוד טוב במערכות כמו זו שתוארה כאן.
יש גם נקודות לתשומת לב:
- זה תלוי בחלקו במימוש של ה-TCP stack
- timestamps לבד לא מעלים את ה-packet loss עצמו
- אם השכבה הפיזית או ציוד הביניים לקויים, הסיבה השורשית נמצאת במקום אחר
- כדאי לבדוק בנפרד גם SACK, דרייבר ה-NIC, הגדרות offload ובעיות בצד ה-switch
עם זאת, במערכות שבהן “ה-loss לא אפס” אך “מה שכואב באמת זו ההמתנה בסדר גודל של שניות” — כמו במקרה הזה — זה יכול לעזור באופן משמעותי.
6. מה עשינו בפועל
6.1. הפעלת timestamps
כפתרון, וידאנו ששני קצות החיבור יכולים לסכם את timestamps option. במערכות Windows זה לפעמים מטופל כ-RFC 1323 option, והוא מושפע מהגדרות מערכת ההפעלה והרשת.
השלבים המדויקים. קודם בודקים מה המצב הנוכחי:
netsh interface tcp show global
בפלט מופיע פריט של RFC 1323 timestamps, ובודקים אם הוא מופעל. כדי להפעיל, ב-command prompt עם הרשאות Administrator:
netsh interface tcp set global timestamps=enabled
עבור timestamps אפשר לציין שלושה ערכים: disabled / enabled / default, כאשר default מחזיר לברירת המחדל של המערכת.
כדי לבדוק ולהגדיר דרך PowerShell:
Get-NetTCPSetting | Select-Object SettingName, Timestamps, MinRtoMs, InitialRtoMs
Set-NetTCPSetting -SettingName InternetCustom -Timestamps Enabled
עבור Timestamps אפשר לציין Enabled / Disabled. ה-SettingName שניתן לשנות משתנה לפי גרסת Windows, ולכן לא כדאי להריץ Set- ישר — קודם בודקים עם Get-NetTCPSetting אילו שמות קיימים בפועל. העברת שם שלא קיים תעצור את הפעולה שם.
בסביבות ישנות, אם בודקים ישירות דרך ה-Registry, מדובר בערך Tcp1323Opts (מסוג REG_DWORD) תחת המפתח הבא:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
המשמעות של הערכים: 0 — RFC 1323 options מבוטלות, 1 — window scaling בלבד, 2 — timestamps בלבד, 3 — שניהם מופעלים. כדי לא להתבלבל, כדאי לזכור שביט 0 מתאים ל-window scaling וביט 1 מתאים ל-timestamps.
יש שלוש נקודות לתשומת לב בעת ההגדרה:
- זה עובד רק על חיבורים חדשים. timestamps מסוכמים ב-3-way handshake, כך שזה לא משפיע על חיבורים שכבר קיימים. צריך לפתוח מחדש את החיבור בצד ההתקן
- זה לא יעבוד אם שני הצדדים לא תומכים. גם אם מפעילים רק בצד ה-host, אם המצלמה לא מחזירה TSopt ב-SYN/ACK, זה לא ישמש באותו חיבור
- ההגדרה גם משנה את אופי החיבור. timestamps מגדילות את כותרת TCP, כך שכמות הנתונים שנכנסת ל-segment אחד קטנה מעט
עם זאת, בפועל “TSopt מופיע בפועל ב-packet של SYN / SYN-ACK” חשוב יותר מ”מוצג כמופעל במסך ההגדרות”. זה באמת המצב.
flowchart TB
accTitle: שלוש נקודות לתשומת לב בהגדרת timestamps
accDescr: שלוש נקודות בהגדרת timestamps: ההגדרה עובדת רק על חיבורים חדשים כי היא מסוכמת ב-3-way handshake, שני הצדדים חייבים לתמוך בה, והכותרת גדלה כך שכמות הנתונים ב-segment קטנה מעט.
care["שלוש נקודות לתשומת לב"] --> n1["עובד רק מחיבורים חדשים"]
care --> n2["נדרשת תמיכה בשני הצדדים"]
care --> n3["הכותרת גדלה והנתונים קטנים מעט"]
n1 -.-> re["יש לפתוח מחדש את חיבור ההתקן"]
איור 12: ההגדרה לבדה לא מספיקה. צריך גם לפתוח מחדש את החיבור וגם לוודא תמיכה בצד השני.
6.2. בדיקת TSopt ב-SYN / SYN-ACK
אחרי ההפעלה בדקנו שלוש נקודות:
- האם יש TSopt ב-SYN של החיבור הבעייתי
- האם גם צד ה-SYN/ACK מחזיר TSopt
- האם TSopt ממשיך להופיע גם ב-data segments וב-ACK שבאים אחר כך
רק אחרי אימות הנקודות האלה אפשר לומר ש”timestamps באמת בשימוש בחיבור הזה”.
6.3. איפה לבדוק כשזה עדיין לא עוזר
גם אחרי הפעלת timestamps, במקרים הבאים השיפור עשוי להיות חלש:
- שיעור ה-loss עצמו גבוה
- ציוד ביניים שובר, מפיל או משנה TCP options
- יש בעיה אחרת סביב ה-NIC / הדרייבר / הגדרות ה-offload
- האפליקציה תולה את כל התהליך בקריאה סינכרונית בודדת, כך שהמתנה אחת נראית כ-stall כולל
- בפועל הגורם העיקרי אינו TCP, אלא עצירת עיבוד בצד המצלמה או גודש בתור הפנימי של ההתקן
לכן, קל יותר להתקדם עם הטיפול לפי הסדר הבא:
- קודם כול, לוודא ב-wire שיש המתנה ל-retransmission
- לבדוק אם התבצע משא ומתן על TSopt
- להפעיל timestamps ולבדוק את הפער בשיפור
- אם עדיין נשאר, לטפל בנפרד במקור ה-loss ובתכנון האפליקציה
flowchart TB
accTitle: הסדר לביצוע הטיפול
accDescr: קודם בודקים ב-wire המתנה ל-retransmission, בודקים אם בוצע משא ומתן על TSopt, מפעילים timestamps ובודקים את פער השיפור, ואם עדיין נשארת בעיה מטפלים בנפרד במקור ה-loss ובתכנון האפליקציה.
s1["בדיקת המתנה ל-retransmission ב-wire"] --> s2["בדיקת משא ומתן על TSopt"]
s2 --> s3["הפעלת timestamps ובדיקת השיפור"]
s3 --> s4["אם נשאר, טיפול נפרד במקור ה-loss ובתכנון"]
איור 13: סדר של בדיקה, משא ומתן, הפעלה ובדיקת מה שנשאר מקל על פירוק הגורם כשההפעלה לא עוזרת.
7. נקודות בדיקה ב-Wireshark
הנה display filters שנוחים לשימוש בפירוק:
tcp.stream eq <stream היעד>
tcp.analysis.retransmission
tcp.analysis.fast_retransmission
tcp.analysis.lost_segment
tcp.options.timestamp.tsval
tcp.options.timestamp.tsecr
יש כמה טיפים לאופן ההסתכלות:
- מצמצמים ל-
tcp.streamשל החיבור היעד בלבד - מציגים את
Time delta from previous displayed packetורואים ישירות כמה שניות נמשך ה-stall - בודקים אם
Retransmissionמופיע ברגע הבעייתי - בודקים אם TSopt סוכם ב-SYN / SYN-ACK בתחילת החיבור
- בודקים אם
TSecrחוזר ב-ACK
נכתוב גם איך זה נראה על המסך, במילים. אחרי שמתרגלים, אפשר לזהות את המקרה הזה במבט אחד.
| היכן מסתכלים | איך זה נראה |
|---|---|
| עמודת ה-Info ברשימת ה-packets | על packets של retransmission מופיע [TCP Retransmission] |
| צבע השורה | זה תואם לכלל הצביעה ברירת המחדל של Wireshark “Bad TCP”, כך שהשורה מקבלת רקע שחור וטקסט אדום. אפשר לתפוס את זה גם במבט חטוף |
| חלונית הפרטים | בוחרים את השורה, פותחים את Transmission Control Protocol, ובתוכו את SEQ/ACK analysis — שם מופיע ציון שה-packet זוהה כ-retransmission |
| פער הזמן | הצגת Time delta from previous displayed packet כעמודה מראה כמה שניות עברו מה-packet המוצג הקודם. כאן רואים רצף של שנייה, שתי שניות |
| ה-Options של ה-SYN | בוחרים את שורת ה-SYN, פותחים את Options, ובודקים אם יש פריט Timestamps — כך יודעים אם יש TSopt |
הרצף האופייני נראה כך: תחילה שורה עם אותו Seq מופיעה שוב אחרי שנייה, ואז שוב אחרי שתי שניות נוספות, ומיד אחרי השורה האחרונה חוזר ה-ACK, ומשם מתחדשים חילופי הדברים הרגילים. אם “פער השניות הריק” הזה תואם את הזמן שבו התגובה נעצרה בלוג האפליקציה, כמעט אפשר לקבוע את החשוד.
כשמצליבים בין הלוג לבין ה-packets, יש לשים לב גם להפרש בין בסיס הזמן של האפליקציה לבין בסיס הזמן של ה-capture. אם יש הסטה כאן, קל להאשים אירוע לא קשור.
flowchart TB
accTitle: התהליך לקביעת החשוד ב-Wireshark
accDescr: מצמצמים ל-tcp.stream של החיבור היעד, מסתכלים על עמודת פער הזמן כדי לראות ישירות את משך ה-stall, מוודאים שורות retransmission לאותו Seq, ואם הפער תואם את זמן ה-stall בלוג האפליקציה החשוד כמעט מוכרע.
filt["צמצום ל-tcp.stream של החיבור"] --> delta["הסתכלות על עמודת פער הזמן"]
delta --> re["וידוא שורות retransmission לאותו Seq"]
re --> match{"תואם את זמן ה-stall באפליקציה?"}
match -->|"כן"| fix["החשוד כמעט מוכרע"]
match -->|"לא"| other["לחשוד בהפרש זמן או בגורם אחר"]
איור 14: לצמצם, להסתכל על פער הזמן, ולהצליב. בשלושה צעדים אלה קובעים את זהות “פער השניות הריק”.
8. איך לבחור כיוון, בגדול
| סימפטום | הגורם החשוד הראשון | מה לבדוק תחילה |
|---|---|---|
| stall מדי פעם בסדר גודל של שניות | המתנה ל-RTO ב-TCP | לבדוק retransmission ופער זמן ב-packets |
| stall כמעט באותו תזמון בכל פעם | המתנה בתוך האפליקציה, עיבוד בצד ההתקן, timeout קבוע | לבדוק threads, קריאות SDK ולוגי התקן |
| מחמיר רק בעומס גבוה | CPU, GC, גודש בתור | לבדוק CPU, interrupts, זיכרון ואורך תור |
| גרוע בבת אחת על פני חיבורים רבים | השכבה הפיזית, switch, ציוד ביניים | לבדוק NIC, כבלים, סטטיסטיקת פורטים ולוגי ציוד ביניים |
| שינוי הגדרה לא שינה כלום | TCP option לא סוכם בפועל | לבדוק שוב את SYN / SYN-ACK |
השורה האחרונה קורית ממש הרבה. תחושת הסיפוק מכך ששיחקתם עם ההגדרות, והעובדה שהיא באמת בשימוש ב-wire — הם שני דברים שונים.
9. סיכום
הנקודות העיקריות הפעם:
- “לפעמים נתקע לכמה שניות” יכול להיות המתנה ל-TCP retransmission, ולא stall של האפליקציה
- אם משך ה-stall תואם את אופן ההמתנה של ה-RTO ומופיע
Retransmission, זו השערה חזקה למדי - TCP timestamps option היא מנגנון של RTTM ו-PAWS, שגם מסירה את העמימות במדידת RTT בזמן retransmission
- במקרה הזה, הפעלת timestamps לפי RFC1323 קיצרה את הזמן שבו ה-RTO נשאר שמרני מדי
דרכי פעולה שכדאי להימנע מהן:
- לקבוע את החשוד ל-stall בתקשורת רק לפי לוגי האפליקציה
- להסתכל רק על הגדרות מערכת ההפעלה בלי לבדוק את ה-packets עצמם
- לחשוב שהפעלת timestamps מעלים גם את מקור ה-loss
דרכי פעולה שעובדות בפועל:
- קודם כול, להסתכל על ה-wire
- לבדוק את הצורה של ה-retransmission וזמן ההמתנה
- לוודא משא ומתן על TSopt
- גם אחרי השיפור, לטפל בנפרד במקור ה-loss ובתכנון האפליקציה
במילים אחרות, בסוג הזה של תקלות עדיף קודם “לזהות איפה ממתינים” ולא “להאיץ”. רק אם לא מפספסים את הנקודה הזו, החקירה מתקצרת משמעותית.
10. מקורות
- 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
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
Handle leak באפליקציית מצלמה תעשייתית שקורסת אחרי ריצה ארוכה
איך בוחנים אפליקציית Windows שקורסת פתאום אחרי ריצה ארוכה, דרך מקרה של אפליקציית בקרת מצלמה תעשייתית: איך מוצאים handle leak ואיך מתכננים...
מה Not Responding באמת אומר — איך Windows מחליט שיש hang, ואיך לתכנן אפליקציות שלא נתקעות
Windows מסמן window כ-Not Responding אחרי 5 שניות בלי שליפת message ומציג ghost window: השיפוט, סיבות ה-hang, תכנון ה-UI thread, והחקירה.
WPR/WPA בפועל — מבוא לחקירת "כל ה-PC איטי" על פני כל המערכת
חוקרים PC איטי או startup איטי ש-Task Manager לא מסביר עם ETW trace ברמת ה-OS: מצלמים ב-wpr.exe, ואז קוראים CPU, המתנות ו-I/O דיסק ב-WPA.
איך משאירים לוגים ו-crash dump כשאפליקציית Windows קורסת
איך משלבים לוג רגיל, fatal crash marker, WER LocalDumps ותהליך watchdog, כדי שאפילו כשאפליקציית Windows קורסת מ-exception לא צפוי או מ-bu...
איך אוספים crash dump באפליקציית Windows: WER, ProcDump, WinDbg
איך בוחרים ומשתמשים ב-WER LocalDumps, ProcDump, MiniDumpWriteDump ו-WinDbg כדי לחקור קריסות באפליקציות Windows שקשה לשחזר, כולל נקודות תפ...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
חקירת תקלות ובעיות בריצות ארוכות
תקלות לסירוגין, אבחון תקשורת, תקיעות בריצות ארוכות ובדיקת נתיבי כשל.
חקרי מקרה קשורים
חקרי המקרה האלה מציגים גישה דומה לניתוח, לתעדוף או לעיצוב מחדש.
כיצד בודדנו ניתוקי תקשורת של כמה שניות
חקר מקרה על ניתוק נדיר, שהופרד בין המתנת שידור חוזר לבין תנאי מערכת ההפעלה.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
חקירת תקלות ואיתור גורמים
פירוק stall בתקשורת שקשה לשחזר, לפי packets וראיות — נושא שיושב ישירות על חקירת תקלות וניתוח סיבה.
פיתוח יישומי Windows
כאפליקציית Windows עם אינטגרציה להתקן, זה מוביל גם לייעוץ על תכנון התקשורת והניטור מצד המימוש.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- מה זה TCP Retransmission?
- מנגנון שבו TCP שולח שוב את אותם הנתונים כשה-ACK על packet שנשלח לא חוזר. אם packet נופל איפשהו בדרך, הצד השולח ממתין ל-ACK, ואם הוא לא מגיע — מחכים שטיימר ה-retransmission (RTO) יפוג ורק אז משדרים שוב. מהאפליקציה זה נראה כ"עצירה של כמה שניות", אבל מבחינת TCP זו פשוט המתנה לטיימר עד שה-ACK יגיע. זו צורת stall שכיחה. ב-packet capture רואים את זה כ-TCP Retransmission.
- מה גורם ל-TCP Retransmission?
- הטריגר הישיר הוא packet loss: ה-ACK לא חוזר, ולכן קורה retransmission. את מקור ה-loss בודקים בנפרד — השכבה הפיזית (כבלים ופורטים), ה-NIC והדרייבר או הגדרות ה-offload, ובעיות ב-switch או בציוד ביניים. הפעלת TCP timestamps יכולה לקצר את ההמתנה אחרי retransmission, אבל זה לא קסם שמעלים את ה-loss עצמו, ולכן חקירת מקור ה-loss נשארת נפרדת. יש גם מקרים שבהם ציוד ביניים שובר או מפיל TCP options, וגם מקרים שבהם הגורם העיקרי בפועל הוא עצירת עיבוד בצד ההתקן ולא TCP בכלל.
- למה TCP retransmission עוצר תקשורת לכמה שניות?
- כי טיימר ה-retransmission (RTO) של TCP ממתין באופן שמרני. לפי RFC 6298, ה-RTO ההתחלתי מבוסס על שנייה אחת; אם תוצאת החישוב קטנה מזה, מעגלים כלפי מעלה לשנייה, וכל timeout מכפיל את הערך. בתנאים גרועים רואים המתנה כמו שנייה, שתי שניות, ארבע שניות. בתקשורת בקרה שמבוססת בעיקר על request/response קטנים, לפני שמספיקים Duplicate ACK כדי להיכנס ל-fast retransmit, נוטה להיחשף קודם המתנה ל-RTO — וזה מופיע כעצירה נדירה של כמה שניות. הפעלת TCP timestamps option יכולה, במקרים מסוימים, להסיר את העמימות במדידת RTT בזמן retransmission ולקצר את הזמן שבו הערכת ה-RTO נשארת שמרנית מדי.
- איך בודקים TCP Retransmission ב-Wireshark?
- אפשר להשתמש ב-display filters tcp.analysis.retransmission, tcp.analysis.fast_retransmission ו-tcp.analysis.lost_segment. מצמצמים ל-tcp.stream של החיבור הרלוונטי, מציגים את Time delta from previous displayed packet כדי לראות ישירות כמה שניות נמשכה העצירה, ובודקים אם Retransmission מופיע ברגע הבעייתי ואם פער הזמן עד ה-retransmission תואם את משך ה-stall. האם משתמשים ב-TCP timestamps בודקים לפי משא ומתן על TSopt ב-SYN / SYN-ACK בתחילת החיבור. העובדה ש-TSopt נמצא בפועל ב-packets חשובה יותר מזה שההגדרה מוצגת כמופעלת במסך ההגדרות.