اپڊيٽ ٿيل -1 m
כל פקט שאתה שולח עלול ללכת לאיבוד. הוא עלול להגיע פגום, שלא בסדר, פעמיים, או בכלל לא. האינטרנט לא מבטיח דבר.
TCP מבטיח בכל זאת.
כשאתה טוען דף אינטרנט, שולח מייל, או מוריד קובץ, TCP מבטיח שהנתונים שלך יגיעו שלמים, בסדר הנכון, ומלאים — אפילו דרך רשתות שאינן מבטיחות דבר. איך בונים אמינות מתוך חוסר אמינות? באמצעות אימות.
לחיצת היד התלת-שלבית: הוכחה שאתם שומעים זה את זה
לפני ש-TCP שולח אפילו בייט אחד של נתונים, הוא פותר בעיה יסודית: כיצד שני מחשבים יודעים שהם יכולים לתקשר בפועל?
האינטרנט אינו שיחת טלפון. אין צליל חיוג. כשאתה שולח פקט, אין לך מושג אם הגיע. המחשב האחר אינו יודע שאתה קיים עד שהפקט שלך מגיע — אם הוא מגיע בכלל. לכן TCP פותח בטקס של הוכחה הדדית.
הלקוח שולח פקט SYN (סינכרוניזציה): "אני קיים. אני רוצה לדבר. הנה מספר אקראי שאשתמש בו לעקוב אחר השיחה שלנו."
השרת משיב עם SYN-ACK: "שמעתי אותך. גם אני קיים. הנה המספר האקראי שלי. הגדלתי את שלך באחד כדי להוכיח שבאמת קראתי את הפקט שלך."
הלקוח שולח ACK: "שמעתי שאתה שומע אותי. המספר שלך פלוס אחד. אנחנו מסונכרנים."
שלושה פקטים. שני זרים מעבר לתהום בלתי אמינה הוכיחו שהם שומעים זה את זה. עכשיו הם יכולים לדבר.
המספרים ההתחלתיים האקראיים (Initial Sequence Numbers) מונעים אסון עדין: פקטים מחיבורים ישנים ומתים שמתבלבלים עם נתונים חדשים. אם תמיד היית מתחיל מאפס, פקט מאוחר מחיבור קודם עלול להיראות תקין. מספרים אקראיים הופכים את ההתנגשות הזו לבלתי סבירה באופן אסטרונומי.
העברת נתונים: ממספר כל בייט
לאחר שלחיצת היד מסתיימת, TCP עומד בפני האתגר המרכזי שלו: שליחת נתונים באופן אמין על פני רשתות בלתי אמינות.
הפתרון הוא ניהול ספרים אובססיבי. TCP מקצה מספר רצף לכל בייט — לא לכל פקט, לכל בייט. אם אתה שולח מקטע של 1000 בייטים שמתחיל במספר רצף 5000, הבייטים ממוספרים 5000 עד 5999. המקטע הבא מתחיל ב-6000.
מדוע בייטים במקום פקטים? פקטים יכולים להיות בכל גודל, מפוצלים, משולבים, שנשלחים מחדש בחלקים שונים. על ידי מספור בייטים, TCP יכול לארגן מחדש את הנתונים בצורה נכונה ללא קשר לאופן שבו הם מגיעים. אם בייטים 5000-5999 ו-7000-7999 מגיעים אבל 6000-6999 חסרים, המקבל יודע בדיוק מה נעדר.
המקבל מאשר נתונים עם פקטי ACK: "קיבלתי הכל עד בייט N. שלח לי בייט N הבא." זהו אישור מצטבר — ACK יחיד מאשר את כל הנתונים הקודמים.
- שולח: "הנה בייטים 5000-5999"
- שולח: "הנה בייטים 6000-6999"
- שולח: "הנה בייטים 7000-7999"
- מקבל: "קיבלתי הכל עד 8000"
השולח לא ממתין לכל ACK לפני שליחת עוד. הוא שומר חלון של נתונים שטרם אושרו בתנועה, ממקסם את התפוקה תוך מעקב אחר כל בייט, מוכן לשלוח מחדש כל דבר שלא מקבל אישור.
כשדברים משתבשים: שידור חוזר
פקטים נעלמים. זה לא שאלה של אם, אלא מתי. מנגנוני השידור החוזר של TCP הופכים את הוודאות הזו לבעיה הניתנת לפתרון.
כל מקטע נושא סכום ביקורת — טביעת אצבע מתמטית של תוכנו. המקבל מחשב מחדש את טביעת האצבע הזו. אם היא לא תואמת, הפקט הושחת במהלך ההעברה. TCP פשוט משליך אותו. ללא אישור. עבור השולח, שתיקה פירושה "נסה שוב."
השולח שומר טיימר לכל מקטע שלא אושר. אם הטיימר פג לפני שמגיע ACK, TCP שולח מחדש. פסק הזמן אינו קבוע — TCP מודד ברציפות את זמן הסבב ומתאים את עצמו. חיבור בין שני מחשבים באותו חדר זקוק לפסק זמן קצר יותר מחיבור בין שני קצוות האוקיינוס.
אבל המתנה לפסקי זמן היא איטית. ל-TCP יש מנגנון מהיר יותר: כאשר המקבל מקבל נתונים שלא בסדר, משהו השתבש. אם בייטים 5000-5999 מגיעים, ואחר כך 7000-7999, ואחר כך 8000-8999 — איפה 6000-6999?
המקבל לא יכול לאשר מעבר לפער, אז הוא ממשיך לשלוח "אני צריך את 6000" שוב ושוב. כשהשולח רואה שלושה ACKים כפולים שמבקשים את אותו הבייט, הוא לא ממתין לפסק הזמן. הוא מיד שולח מחדש את המקטע החסר. "שידור חוזר מהיר" זה משחזר פקטים אבודים במילישניות במקום שניות.
Selective Acknowledgment (SACK) מרחיב את זה עוד יותר. במקום לומר רק "אני צריך את 6000," המקבל יכול לומר "אני צריך את 6000, אבל כבר יש לי 7000-8999." השולח יודע בדיוק מה חסר ושולח מחדש רק את זה.
בקרת זרימה: אל תציף את המקבל
אמינות אינה רק עניין של הרשת. מה אם השולח מעביר מהר יותר ממה שהמקבל יכול לעבד?
המקבל עשוי להיות טלפון עם זיכרון מוגבל, שרת שמטפל באלפי חיבורים, או מחשב שהאפליקציה שלו עסוקה בעבודה אחרת. אם נתונים מגיעים מהר יותר ממה שניתן לצרוך אותם, מאגר הקלט מתמלא. פקטים חדשים נמחקים. שידורים חוזרים נמחקים שוב. החיבור נעצר לחלוטין.
TCP פותר זאת עם חלון הקלט — מספר שהמקבל כולל בכל ACK: "יש לי מקום ל-N בייטים נוספים. אל תשלח יותר מזה."
החלון משקף את מרחב המאגר בפועל. כשהאפליקציה קוראת נתונים, החלון גדל. אם האפליקציה נשארת מאחור, החלון מתכווץ. אם המאגר מתמלא לחלוטין, החלון יורד לאפס: "עצור. אני לא יכול לטפל ביותר."
השולח מכבד מגבלה זו לחלוטין. כשהחלון הוא אפס, הוא מפסיק לשלוח נתונים אך שולח מדי פעם פקטי "גישוש חלון" זעירים — רק בודק אם שוחרר מקום. ללא הגישושים האלה, עדכון חלון שאבד עלול לנעול את החיבור לנצח.
בקרת עומס: אל תציף את הרשת
בקרת זרימה מגנה על המקבל. בקרת עומס מגנה על כולם.
לרשת שבין השולח למקבל יש קיבולת מוגבלת. נתבים יכולים להעביר רק כמות מסוימת של פקטים בשנייה. אם השולחים משדרים ביחד יותר ממה שהרשת יכולה לטפל, פקטים מצטברים בתורים של מאגרי הנתב. בסופו של דבר המאגרים גולשים. פקטים נמחקים. שידורים חוזרים מחמירים את העומס. הרשת קורסת.
TCP לא יכול לראות ישירות את קיבולת הרשת. הוא מסיק אותה מהתנהגות. התובנה המרכזית: אובדן פקטים משמעו עומס. אם הפקטים שלך נמחקים, אתה שולח מהר מדי.
השולח שומר חלון עומס — אומדנו לגבי כמות הנתונים שהרשת יכולה לטפל. מגבלת השליחה בפועל היא הקטן מבין חלון העומס וחלון הקלט.
חיבורים חדשים מתחילים בזהירות. חלון העומס מתחיל קטן — מקטע אחד או שניים. כשה-ACKים מגיעים בהצלחה, החלון גדל באופן אקספוננציאלי ("התחלה איטית"). מקטע אחד הופך לשניים, שניים לארבעה, ארבעה לשמונה. זה נשמע אגרסיבי, אבל זה זהיר: אתה בוחן את קיבולת הרשת מאפס.
ברגע שהחלון מגיע לסף (או שמתרחש אובדן פקטים), TCP עובר ל"הימנעות מעומס" — צמיחה ליניארית. מקטע אחד נוסף לכל סיבוב שלם. עלייה זהירה ומדודה.
כשמתרחש אובדן, TCP נסוג בחדות. פסק זמן מאפס את החלון למינימום ומתחיל את ההתחלה האיטית מחדש. שלושה ACKים כפולים חוצים את החלון לחצי אך מדלגים על ההתחלה האיטית — "שחזור מהיר."
הריקוד הזה — בחינה כלפי מעלה, נסיגה בעת אובדן, בחינה שוב — מוצא את קיבולת הרשת ועוקב אחריה ככל שהתנאים משתנים. אלגוריתמים מודרניים כמו CUBIC ו-BBR משתמשים במודלים מתוחכמים יותר, אך העיקרון המרכזי נשאר: אובדן פקטים פירושו "האט."
סיום החיבור: פרידה מסודרת
חיבורי TCP מסתיימים בכוונה כשם שהם מתחילים. כל צד יכול ליזום סגירה על ידי שליחת פקט FIN (סיום): "אין לי עוד נתונים לשלוח."
הצד השני מאשר את ה-FIN אך אולי עדיין לא סיים לשלוח. TCP תומך בחיבורים חצי-סגורים — כיוון אחד הסתיים, השני עדיין פעיל. שלחת את בקשת ה-HTTP שלך, אבל אתה עדיין מחכה לתשובה.
כששני הצדדים שלחו ואישרו FINים, החיבור סגור לחלוטין. אבל יש ערובה אחרונה: הצד ששלח את ה-ACK האחרון נכנס למצב TIME_WAIT למשך מספר דקות. ה-ACK האחרון הזה אולי אבד. אם הצד השני שולח מחדש את ה-FIN שלו, מישהו צריך להיות שם כדי לאשר אותו.
לשעת חירום, TCP תומך בסגירה פתאומית דרך פקטי RST (איפוס). ללא משא ומתן, ללא המתנה — החיבור נהרס מיידית.
פרוטוקול האמון
TCP לא סומך על הרשת. הוא סומך על הפרוטוקול.
כל מנגנון משרת אימות. לחיצת היד מוכיחה נגישות הדדית. מספרי הרצף מוכיחים סדר. אישורים מוכיחים קבלה. סכומי הביקורת מוכיחים שלמות. שידור חוזר מוכיח התמדה. בקרת זרימה מוכיחה שהמקבל מוכן. בקרת עומס מוכיחה שהרשת יכולה לטפל בעומס.
זו הסיבה ש-TCP מניע את רוב האינטרנט. לא משום שהוא מהיר — UDP מהיר יותר. לא משום שהוא פשוט — UDP פשוט יותר. אלא משום שכשאתה צריך לדעת שהנתונים שלך הגיעו, שלמים, בסדר, מבלי להציף אף אחד בשרשרת, TCP מספק וודאות מתמטית שבה הרשת לא מספקת כלום.
המורכבות היא הנקודה. אמינות לא נובעת מאיחולים. היא נובעת מאימות, אישור, ונכונות לנסות שוב כשדברים משתבשים.
שאלות נפוצות על TCP
מדוע TCP משתמש בלחיצת יד תלת-שלבית ולא בשתי הודעות?
שתי הודעות היו מוכיחות תקשורת חד-כיוונית: הלקוח יכול להגיע לשרת. אבל TCP זקוק להוכחה דו-כיוונית. ההודעה השלישית מוכיחה שתגובת השרת הגיעה בחזרה. ללא זה, השרת היה מקצה משאבים לחיבור שאולי לא יעבוד בשני הכיוונים. שלושה פקטים הם החלפה המינימלית שמוכיחה נגישות הדדית.
מה קורה אם ACK אובד?
טיימר השידור החוזר של השולח פג, והוא שולח מחדש את הנתונים. כשהנתונים שנשלחו מחדש מגיעים, המקבל שולח ACK נוסף. נתונים כפולים אינם מזיקים — מספרי הרצף מאפשרים למקבל לזהות אותם ולהשליך אותם. המערכת מרפאת את עצמה: ACKים אבודים מפעילים שידורים חוזרים, שמפעילים ACKים חדשים.
מדוע TCP מפרש אובדן פקטים כעומס?
ברוב הרשתות, אובדן פקטים מתרחש כי מאגרי הנתב גולשים — נשלחים יותר מדי נתונים. בעוד שאובדן יכול להתרחש מסיבות אחרות (הפרעה אלחוטית, למשל), עומס הוא הגורם הדומיננטי ברשתות קוויות. התגובה השמרנית של TCP עשויה לעיתים להפחית מהירות שלא לצורך, אבל היא מונעת קריסת עומס, שתהיה חמורה בהרבה.
כיצד TCP מטפל בפקטים שמגיעים שלא בסדר?
המקבל משתמש במספרי רצף כדי לארגן מחדש את הנתונים בצורה נכונה, ללא קשר לסדר ההגעה. פקטים שמגיעים שלא בסדר מאוחסנים במאגר עד שמקטעים חסרים מגיעים. המקבל מאותת על הפער על ידי שליחת ACKים כפולים עבור הבייט הרציף האחרון שהתקבל, מה שמפעיל שידור חוזר מהיר. כש-SACK מופעל, המקבל מדווח בדיוק אילו מקטעים הגיעו, מה שהופך את השחזור ליעיל עוד יותר.
ڇا هي صفحو مددگار هو؟