עודכן לפני חודש
הפעל ss -tan על כל שרת ותראה משהו שרוב האנשים מדלגים עליו: עמודה של מצבים. ESTABLISHED. TIME_WAIT. CLOSE_WAIT. SYN_SENT.
אלה לא רק תוויות. הן שיחה שקפאה בזמן. כל מצב אומר לך מי דיבר אחרון ומה הוא מחכה לשמוע בחזרה.
מה הם מצבי חיבור בפועל
חיבורי TCP הם שיחות בין שני מחשבים. כמו כל שיחה, יש להם התחלה ("שלום"), אמצע (תקשורת בפועל), וסוף ("להתראות"). מצבי חיבור מסמנים היכן אתה נמצא בשיחה הזו.
ל-UDP אין מצבים כי ל-UDP אין שיחות. הוא יורה חבילות לחלל הריק ומקווה שיגיעו. אין לחיצת יד, אין אישור, אין מצב לעקוב אחריו.
אבל TCP מבטיח מסירה. כדי לעשות זאת, שני הצדדים צריכים להסכים על מה שקורה בכל רגע. מצבים הם ההסכם הזה שנעשה גלוי לעין.
המצבים
LISTEN — שרת עם ידו כוסה לאוזנו, ממתין. "אני מוכן אם מישהו רוצה לדבר." כל שרת אינטרנט על פורט 443, כל SSH daemon על פורט 22, מתחיל כאן.
SYN_SENT — הלקוח דפק על הדלת. עכשיו הוא עומד בחוץ, ממתין. אם הוא ממתין יותר מדי זמן, משהו לא בסדר: השרת מושבת, חומת אש בלעה את החבילה, או הכתובת לא קיימת.
SYN_RECEIVED — השרת שמע את הדפיקה וענה "מי שם?" עכשיו הוא מחכה ללקוח לסיים את לחיצת היד. אלף חיבורים תקועים כאן פירושם אלף לחיצות יד שנשארו תלויות באוויר — לעיתים קרובות מדובר במתקפת SYN flood, שבה בקשות חיבור מזויפות משאירות שרתים שמושיטים ידיהם ללחיצות יד שלעולם לא יושלמו.
ESTABLISHED — השיחה מתרחשת. נתונים זורמים בשני הכיוונים. זהו המצב התקין, זה שרוצים לראות.
FIN_WAIT_1 — צד אחד אמר "סיימתי לדבר" אבל עדיין לא קיבל אישור.
FIN_WAIT_2 — הפרידה אושרה, אבל הצד השני עדיין לא אמר את שלומו.
CLOSE_WAIT — הצד המרוחק ניתק. הצד שלך אישר זאת. אבל האפליקציה שלך עדיין לא סגרה את החיבור. זה כמו רוח רפאים — הצד השני כבר הלך, אבל האפליקציה שלך עדיין מחזיקה את הדלת פתוחה, מחכה למישהו שלא יחזור. חיבורים רבים תקועים כאן מסמנים באג באפליקציה שלך.
TIME_WAIT — החיבור הסתיים, אבל חבילות תועות מהשיחה הישנה עשויות עדיין להסתובב ברשת. TIME_WAIT מונע מהן לבלבל שיחה חדשה שעושה שימוש חוזר באותם מספרי פורטים. על Linux, זה נמשך 60 שניות.1
CLOSED — נגמר. השיחה כלל לא התקיימה מבחינת המערכת.
איך לבדוק
על Linux:
על macOS:
לספירת חיבורים לפי מצב:
זה מראה לך את תמונת מצב השיחות של השרת שלך במבט אחד.
מה הדפוסים אומרים
מאות SYN_SENT — החיבורים היוצאים שלך לא מגיעים ליעדם. חומת אש? בעיית ניתוב? שרת מת בצד השני?
מאות CLOSE_WAIT — האפליקציה שלך לא מנקה אחרי עצמה. הצדדים המרוחקים סגרו את החיבורים שלהם; האפליקציה שלך מעולם לא שמה לב או מעולם לא הגיבה. תקן את הקוד שלך.
אלפי TIME_WAIT — לאו דווקא בעיה. שרתים עמוסים צוברים אותם באופן טבעי. אבל אם פורטים אפמריים אוזלים לך (Linux משתמש כברירת מחדל בטווח של כ-28,000 פורטים בין 32768 ל-60999),2 תצטרך להפעיל שימוש חוזר בפורטים או להרחיב את הטווח.
חיבורי ESTABLISHED תקועים שלא מעבירים נתונים — השיחה נעצרה אבל אף צד לא הודה בכך. הפעל TCP keepalive לזיהוי וניקוי הזומבים האלה.
SYN_RECEIVED שמצטבר — או שאתה תחת מתקפה (SYN flood) או שאתה חווה עומס תעבורה שמציף את תור ה-SYN שלך. הגדל את ה-backlog. הפעל SYN cookies.
שתיקת UDP
שקעי UDP מופיעים בפלט ss, אבל אין להם מצבים. אין ESTABLISHED, אין TIME_WAIT, אין שיחה לעקוב אחריה. השקע פתוח או לא. חבילות מגיעות או לא.
זה מה שהופך את UDP למהיר — אין עלות לחיצת יד, אין מצב לתחזק. זה גם מה שהופך אותו לעיוור. אם חבילות נעלמות, UDP לא יודע ולא אכפת לו. אפליקציות שמשתמשות ב-UDP (DNS, הזרמת וידאו, משחקים) חייבות לטפל בעצמן במהימנות, אם הן זקוקות לה.
התובנה
מצבי חיבור הם זהב אבחוני כי הם חושפים כוונה. SYN_SENT פירושו "מנסה להתחבר." CLOSE_WAIT פירושו "שכח לנתק." TIME_WAIT פירושו "זה עתה סיים."
כשמשהו מתקלקל, המצב אומר לך היכן בשיחה קרה השבר. זה לרוב מספיק לזהות את הבעיה — חומת אש, באג באפליקציה, בעיית רשת, או מיצוי משאבים — בלי לנחש.
בפעם הבאה שירות תוקע, בדוק את המצבים. המחשבים מנסים לספר לך מה השתבש.
שאלות נפוצות על מצבי חיבור TCP
למה יש לי כל כך הרבה חיבורי TIME_WAIT?
חיבורי TIME_WAIT הם נורמליים — הם מונעים מחבילות ישנות להפריע לחיבורים חדשים שעושים שימוש חוזר באותם מספרי פורטים. שרתים עמוסים צוברים אלפים מהם. זו בעיה רק אם פורטים אפמריים אוזלים לך, מה שמתבטא בכשל של חיבורים חדשים להיווצר.
כיצד אני מתקן חיבורי CLOSE_WAIT שמצטברים?
CLOSE_WAIT פירושו שהאפליקציה שלך קיבלה הודעה שהצד המרוחק סגר את החיבור, אבל לא סגרה את הצד שלה. זה תמיד באג באפליקציה. התיקון הוא בקוד שלך: ודא שאתה סוגר שקעים כראוי כשאתה מזהה שהצד המרוחק התנתק.
מה ההבדל בין FIN_WAIT ל-TIME_WAIT?
מצבי FIN_WAIT פירושם שהחיבור בתהליך סגירה פעיל — צד אחד נפרד, ואתה מחכה לאישור או לפרידה של הצד השני. TIME_WAIT מופיע לאחר שהחיבור נסגר לחלוטין, ומספק חיץ בטיחות לפני שמספרי הפורטים יכולים לשמש שוב.
האם אני יכול לקצר את משך TIME_WAIT כדי לפנות פורטים מהר יותר?
על Linux, משך 60 השניות של TIME_WAIT מקודד קשיח בתוך הקוד ולא ניתן לשינוי ישיר. פתרונות טובים יותר כוללים הפעלת tcp_tw_reuse, מאגר חיבורים, או הרחבת טווח הפורטים האפמריים שלך עם net.ipv4.ip_local_port_range.
מקורות
האם דף זה היה מועיל?