REBUILD://NET المكدّس 0/8RTL · AR / أوامر · ? اختصارات live

المرحلة 03 — الميل الأخير

لاحظ

الطبقة التي نبنيها: Transport (L4). وفيها يولد: الـ port، الـ socket، ثم أعظم مفترق في المنهج — TCP مقابل UDP، مشتقّاً من سؤالٍ واحد: «هل أحتاج أن أثق أن البيانات وصلت؟».

النبذة

الـ IP أوصل الحزمة للجهاز. لكن الجهاز ليس كياناً واحداً — هو عشرات البرامج الجائعة للبيانات في آنٍ واحد. هذه المرحلة تحلّ مشكلتين متتاليتين: (١) أيُّ برنامج يأخذ الحزمة؟ (٢) وهل نضمن وصولها سليمةً مرتّبة، أم نرسل ونمضي؟


اللغز الأول: مشكلة الفرز

حاسب صديقتك (Dest IP = 172.16.20.10) يشغّل الآن: متصفّحاً يحمّل صفحتين، وSpotify، وجلسة SSH، ولعبة. وصلت أربع حزم IP، كلها وجهتُها 172.16.20.10. نظام التشغيل يمسكها أربعتها.

أنت نظام التشغيل. كيف تقرّر أن هذه الحزمة للمتصفّح وتلك لـ SSH؟ المعلومة الوحيدة المضمونة في رأس الـ IP هي عنوانا المصدر والوجهة. عنوان الوجهة واحدٌ للجميع (172.16.20.10). لا يكفي.

صمّم آليةً للفرز قبل أن تُكمل.


الدرس

ليش وُلد الـ Port (الرقم الثاني)

حلّك لا بد أنه: «نضيف رقماً ثانياً يُعرّف الوجهة داخل الجهاز، ويعلن كل برنامجٍ أي رقمٍ يخصّه». اخترعتَ الـ port.

الآن الفرز ممكن: حزمةٌ لـ port 443 ← المتصفّح (HTTPS)، لـ port 22 ← SSH.

الـ Socket: العنوان الكامل لطرفٍ واحد

لاحظ

(IP + port) = socket. — هذا الذي يذكره هولبرتون، مشتقٌّ الآن: الـ IP وحده يصل للجهاز، والـ port وحده بلا معنى عبر الشبكة. اجتماعهما هو الإحداثي الكامل لطرفٍ واحد من محادثة: 172.16.20.10:443.

والأعمق: ما الذي يميّز محادثةً عن أخرى؟ تخيّل أنك فتحت تبويبين للمتصفّح لنفس الخادم 93.184.216.34:443. وجهتهما متطابقة! كيف لا تختلط ردودهما؟

الجواب: المحادثة لا تُعرَّف بـ socket واحد، بل بـ الرباعية (4-tuple):

text
(IP المصدر، port المصدر، IP الوجهة، port الوجهة) 172.16.20.10 : 51000 → 93.184.216.34 : 443 ← التبويب الأول 172.16.20.10 : 51001 → 93.184.216.34 : 443 ← التبويب الثاني ↑ مختلف

نظام التشغيل يختار منفذ مصدرٍ عابراً (ephemeral) مختلفاً لكل اتصالٍ صادر (عادةً من المدى 32768–60999 على Linux). فتفترق المحادثتان بمنفذ المصدر. (مع البروتوكول، تصير خماسية 5-tuple — لكن الفكرة هي هي.)

ليش بعض المنافذ «معروفة»: 22، 80، 443

حين يبدأ عميلٌ (client) اتصالاً بـخادم (server)، يجب أن يعرف أي بابٍ يطرق مسبقاً — الخادم لم يخبره برقم منفذه عبر قناةٍ أخرى. فلو كان منفذ الخادم عشوائياً، لما عرف أحدٌ كيف يصل لموقع! الحل: نتّفق عالمياً على منافذٍ قياسية للخدمات الشائعة:

text
22 → SSH (الإدارة عن بُعد، مشفّر) 80 → HTTP (الويب، غير مشفّر) 443 → HTTPS (الويب، مشفّر)

احفظ هذه الثلاثة (هولبرتون يطلبها صراحةً). البقية في reference-cards.md، لكن لا تحفظها — افهم المبدأ.

لاحظ

التشبيه (ثم نهدمه): هولبرتون يقول «الـ IP عنوانك، والمنافذ أبواب ونوافذ بيتك». مدخلٌ جيد. الآلية الحقيقية وراءه: الـ IP يوصل للمضيف، والمنفذ يفرز داخله بين الخدمات. والباب 80 «معروف» لأن العميل يجب أن يطرقه دون أن يُدلّ عليه.

المنافذ 0–1023 = well-known / privileged. على أنظمة Unix، لا يستطيع الربط (bind) عليها إلا عمليةٌ بصلاحية root. السبب تاريخي-أمني: لو سُمح لأي مستخدمٍ عادي بالاستماع على المنفذ 80، لانتحل خدمةَ الويب الرسمية للنظام وخدع المستخدمين.

لاحظ

هذه الخبيئة هي بالضبط لماذا ستحتاج sudo في تاسكات هولبرتون: الاستماع على المنفذ 98 (basics_1 task 2)، ورؤية كل المنافذ/العمليات (basics_0 task 4). احتفظ بها — ستفهم رسالة الخطأ قبل أن تقع فيها.


اللغز الثاني (قلب المرحلة): اصنع الثقة فوق اللاثقة

حقيقةٌ مزعجة عن كل ما تحته: الـ IP بذل-جهدٍ-فقط (best-effort). لا يَعِد بشيء. الحزمة قد: تُفقَد (راوترٌ ممتلئ رماها)، تصل مكرّرة، تصل بترتيبٍ مقلوب، تصل تالفة. تذكّر مشاكل المرحلة 00 (و، ز) — لم تُحَلّ بعد على مستوى الطرف-للطرف!

مهمّتك: عندك قناةٌ تفقد وتعيد وتقلب الترتيب. تريد أن تنقل ملفاً 1 ميغابايت إلى الطرف الآخر بحيث يصل كاملاً وبالترتيب الصحيح. صمّم البروتوكول. ما الحقول التي تضيفها لكل قطعة؟ كيف تكتشف الفقد؟ كيف تعيد الترتيب؟ كيف لا تُغرق المستقبِل؟

لا تكمل حتى تكتب تصميمك. ستقع في نفس المعضلات التي واجهها مصمّمو TCP في السبعينيات — وهذا المقصود.

ما الذي اخترعتَه (إنه TCP)

قارن تصميمك بهذه اللبنات — لا بد أنك وصلت لأكثرها:

  1. أرقام تسلسل (sequence numbers): رقمٌ لكل بايت/قطعة، فيرتّبها المستقبِل ويكتشف المفقود والمكرّر. (حلّ «الترتيب المقلوب» و«التكرار».)
  2. إقرارات (ACK): يقول المستقبِل «استلمتُ حتى البايت N». إن لم يصل ACK خلال مهلة ← المرسِل يعيد الإرسال (retransmission). (حلّ «الفقد».)
  3. التحكّم بالتدفّق (flow control): يعلن المستقبِل حجم ما يتّسع له (window) فلا يُغرَق. (حلّ مشكلة 00-ز.)
  4. التحكّم بالازدحام (congestion control): يبدأ المرسِل بطيئاً ويتسارع تدريجياً، ويتراجع عند ضياعٍ يشي بازدحام الشبكة. («هل أزيد المعدّل؟»)

هنّأت نفسك: اخترعتَ TCP (Transmission Control Protocol).

إجابة هولبرتون

جواب هولبرتون (Task 3):

  • «عامل TCP يقول: هل استلمتَ الصناديق x, y, z؟» ← هذا الـ ACK حرفياً.

(لا «هل أزيد المعدّل؟» — تلك صياغةٌ لمشكلة الازدحام، لكن السؤال الأيقوني لـ TCP هو التحقّق من الاستلام.) اشتققتَه: التحقّق من الوصول هو جوهر «الثقة».

  • TCP = «ينقل ببطءٍ لكن بثقة». الآلية وراء «البطء»: المصافحة + انتظار الإقرارات

+ التحكّم بالازدحام. ليست صفةً سحرية — هي ثمن الضمانات.

والوجه الآخر: UDP — حين لا تريد دفع الثمن

ماذا لو كنت تنقل صوتاً حيّاً؟ لو ضاعت حزمةٌ، إعادتُها متأخّرةً أسوأ من فقدها (صار الكلام قديماً). أنت لا تريد المصافحة ولا الإقرارات ولا الانتظار. تريد: «خذ هذه الحزمة، أطلقها، انسَها».

هذا UDP (User Datagram Protocol): مجرّد best-effort + منفذا مصدر/وجهة + checksum بسيط. لا مصافحة، لا ترتيب، لا إعادة. سريعٌ، وقد يفقد.

إجابة هولبرتون

جواب هولبرتون (Task 3): UDP = «ينقل بسرعةٍ وقد يفقد بياناتٍ في الطريق». الفرق الجوهري TCP vs UDP الذي يجب أن يثبت: TCP يضيف طبقة ثقة (تسلسل + إقرار + إعادة + تحكّم) فوق IP؛ UDP لا يضيف شيئاً تقريباً. المقايضة: ثقةٌ مقابل سرعة.

المصافحة الثلاثية (3-way handshake): لماذا ثلاث؟

قبل أن يتبادل طرفا TCP بياناتٍ، يتّفقان على أرقام التسلسل الابتدائية:

text
A → B: SYN (أبدأ، رقم تسلسلي الابتدائي = x) B → A: SYN+ACK (أقررتُ x، وأبدأ برقمي الابتدائي = y) A → B: ACK (أقررتُ y)

ليش ثلاث لا اثنتين؟ لأن كلاً منهما يجب أن (١) يعلن رقمه الابتدائي و(٢) يتأكّد أن الطرف الآخر استلمه. رسالتان تكفيان لاتجاهٍ واحد فقط؛ الرسالة الثالثة تثبت للطرف B أن A استلم رقم B. أقلّ من ثلاث يترك أحد الاتجاهين غير مؤكَّد.

الـ IP لا يعرف شيئاً اسمه «اتصال» — يرسل حزماً مستقلّة. «اتصال TCP» ليس أنبوباً ماديّاً بين الجهازين؛ إنه مجرّد حالةٌ مشتركة (أرقام تسلسل ونوافذ) محفوظة في ذاكرة الطرفين. لو أُعيد تشغيل أحدهما، «انقطع الاتصال» — أي ضاعت الحالة، لا أن سلكاً انقطع. لا يوجد خيط. هذا أحد أجمل ما في الشبكات: التجريد يخلق وهم الاستمرارية فوق طبقةٍ بلا ذاكرة.


جرّب: شاهد المنافذ والمحادثات
bash
ss -tlnp # المنافذ المستمعة (TCP, listening, numeric, +PID) — احتجت sudo لـ PID ss -tn # كل اتصالات TCP النشطة: لاحظ الرباعية في عمودي Local/Peer Address

افتح المتصفّح على موقعٍ ما ثم نفّذ ss -tn — سترى محادثاتٍ وجهتُها :443، ومنافذ مصدرٍ عابرة مختلفة. الرباعية التي اشتققتها، حيّةٌ أمامك.

(لاحظ ss و netstat — هاتان أداتا تاسك هولبرتون basics_0 task 4. سنفكّكهما عظماً عظماً في المرحلة 07؛ الآن يكفي أن تربط كل عمودٍ بمفهومٍ بنيتَه: Local Address = socket، State = LISTEN يعني خادمٌ ينتظر.)


لغز الإتقان
  1. على جهازك حادثتان TCP حيّتان لنفس خادمٍ ويب (تبويبان). اكتب الرباعية المحتملة لكلٍّ، وبيّن أي حقلٍ بالضبط يمنع اختلاطهما في نظام التشغيل.
  2. صمّم رأس طبقة النقل بنفسك: لبروتوكول «تيّارٍ موثوقٍ مرتّب فوق best-effort»، اكتب كل حقلٍ في الرأس والمشكلةَ التي يحلّها. ثم افتح رأس TCP الحقيقي (ابحث: TCP header diagram) وطابق: أين أصبتَ؟ ما الحقول التي لم تتوقّعها (مثل Window, flags مثل RST, FIN)؟ كل حقلٍ لم تتوقّعه = درسٌ في مقايضةٍ لم ترها. (هذه خطوة «قارن تصميمك بالمواصفة» — جوهر فهم أي بروتوكول.)
  3. لِمَ يستخدم بثُّ الفيديو الحيّ والألعاب التنافسية UDP غالباً، بينما تحميل ملفٍ أو صفحة ويب يستخدم TCP؟ اربط الجواب بـ«ثمن الثقة».
  4. سؤال خبيث: DNS (الذي سنلتقيه في المرحلة 06) يستخدم UDP عادةً رغم أنه «استعلامٌ مهم». لماذا قد يقبل بروتوكولٌ مهمٌّ المخاطرةَ بالفقد؟ (فكّر: حجم الرسالة، وأن إعادة المحاولة أرخص من إقامة اتصال.)

الخلاصة وموقعك على الشجرة

أنت الآن بنيتَ المكدّس كاملاً: إلكترون ← إطار ← حزمة ← منفذ ← تيّار موثوق. لكنك بنيتَه دون أن تعطيه اسماً. في المرحلة القادمة سأريك أن ما بنيتَه له خريطةٌ شهيرة من سبع طبقات، وأن نصفها أسطورةٌ تربوية والنصف الآخر هو ما يجري فعلاً.

بذرة

ثمّة رسمةٌ من سبع طبقات في كل كتاب شبكات، يحفظها الطلاب بجملةٍ سخيفة («Please Do Not Throw Sausage Pizza Away»). أنت لن تحفظها — لأنك بنيتها. في المرحلة 04 سنضع كل لبنةٍ صنعتها في خانتها على تلك الرسمة، وستكتشف لماذا الواقع يشغّل أربع طبقات لا سبعاً، وأين تكذب الرسمة المدرسية بالضبط.

← التالي: 04-the-stack-has-a-name.md