9.10. TCP -- تدفق موثوق للبايتات¶
إن TCP، أو بروتوكول التحكم في الإرسال (Transmission Control Protocol)، هو الخدمة الأخرى في طبقة النقل القائمة فوق IP. وبينما يمكن وصف UDP بأنه "أرسل حزمة وتمنّ الخير"، فإن TCP هو "افتح اتصالاً بين نقطتي نهاية وعامله كأنبوب ثنائي الاتجاه من البايتات يستقبلها الطرف الآخر بكل تأكيد، وبالترتيب، ومرة واحدة بالضبط". تستخدمه معظم حركة مرور الإنترنت، كما تستخدمه معظم ما تقوم به الكاميرا على الشبكة.
9.10.1. ما الذي يضيفه TCP إلى IP¶
يقوم TCP بأكثر بكثير مما يقوم به UDP. فهو يضيف:
اتصالاً. قبل أن تتدفق أي بيانات، تتبادل نقطتا النهاية مصافحة قصيرة للاتفاق على أنهما تتواصلان. وللاتصال حالة -- "مفتوح"، "مغلق نصفياً"، "مغلق" -- يتتبعها الطرفان.
تسليماً موثوقاً. يتم الإقرار باستلام كل بايت يرسله المرسِل من قبل المستقبِل. وأي شيء لا يُقرّ باستلامه ضمن مهلة محددة يُعاد إرساله. لا يرى التطبيق أبداً بايتاً مفقوداً؛ بل يرى تأخيراً بينما يعيد البروتوكول الإرسال.
تسليماً مرتباً. تصل البايتات بالترتيب نفسه الذي أُرسلت به. وحتى إذا وصلت الحزم إلى المستقبِل بترتيب غير صحيح، فإن TCP يعيد ترتيبها قبل أن يقرأها التطبيق.
التحكم في التدفق. إذا كان المستقبِل بطيئاً، يُطلب من المرسِل أن يبطئ؛ فيتكيف الاتصال مع معدل الطرف الأضعف.
التحكم في الازدحام. إذا بدأت الشبكة في المنتصف بإسقاط الحزم، يتراجع المرسِل حتى تتعافى الأمور. وهذا يمنع أي اتصال واحد من إسقاط وصلة مشبعة.
كل هذا يحدث تلقائياً. إن واجهة Python البرمجية التي يستخدمها التطبيق هي ببساطة send(bytes) و recv(n)؛ ويتولى TCP كل شيء آخر في الخلفية.
9.10.2. المصافحة¶
يُفتح اتصال TCP بتبادل ثلاثي الاتجاه قبل السماح بمرور أي بيانات:
المصافحة الثلاثية الاتجاه. بمجرد أن يقرّ الطرفان بالاستلام، يصبح الاتصال مفتوحاً ويمكن للبيانات أن تتدفق.¶
يرسل العميل حزمة SYN (مزامنة) يطلب فيها الفتح. ويرد الخادم بـ SYN-ACK (مزامنة + إقرار) قابلاً بذلك. ثم يرسل العميل ACK أخيراً للتأكيد. وبعد هذه الجولة، يتفق الطرفان على أن الاتصال مفتوح، وقد زامنا عدّاديهما لتتبع البايتات التي أُرسلت واستُقبلت.
تكلّف المصافحة زمن جولة واحدة من زمن الاستجابة قبل أن يمر أول بايت مفيد. وبالنسبة للشبكات المحلية يكون ذلك جزءاً من الألف من الثانية؛ أما بالنسبة للاتصالات العابرة للقارات فيكون نحو 100 ms. وهذه هي التكلفة الرئيسية لـ TCP، وهي السبب في أن الرسائل القصيرة لمرة واحدة قد يكون من الأفضل أحياناً استخدام UDP لها بدلاً منه.
9.10.2.1. مصافحة الإغلاق¶
تُغلق اتصالات TCP أيضاً بتبادل (حزمة FIN من كل طرف). ويمكن لأي طرف أن يغلق نصفه من الاتصال على نحو مستقل؛ فحالة الإغلاق النصفي التي يكون فيها أحد الطرفين قد انتهى من الإرسال بينما لا يزال الآخر يتحدث هي حالة مشروعة، وإن كانت غير شائعة. وعادة ما يكتفي التطبيق باستدعاء close() ويترك للبروتوكول معالجة تسلسل الإغلاق.
9.10.3. ما الذي لا يضمنه TCP¶
بعض الأمور التي يُفترض أحياناً أن TCP يقوم بها لكنه لا يفعل:
حدود الرسائل. يرسل التطبيق تدفقاً من البايتات، لا تدفقاً من الرسائل. فقد يصل استدعاءان لـ
send(b"hello")على هيئةrecv()واحد يحويb"hellohello"، أو على هيئة استدعاءَيrecv()بأحجام متفاوتة. وإذا أراد التطبيق تأطير الرسائل، فعليه أن يضيف التأطير بنفسه (سطر جديد، أو بادئة طول، أو أي شيء آخر). فإرسال مستندات JSON عبر TCP، على سبيل المثال، يحتاج إلى فصل كل مستند بسطر جديد أو بعلامة أخرى.التشفير. يحمل TCP البايتات التي أعطاها له التطبيق، نصاً صريحاً، طوال الطريق. وإذا كان من الضروري أن تظل المحتويات سرية، فعلى التطبيق أن يغلّف الاتصال داخل TLS (انظر المقابس المشفّرة وبروتوكول TLS).
المصادقة. يتأكد TCP من أن البايتات وصلت سليمة. لكنه لا يقول شيئاً عن من أرسلها. فالمصادقة هي أيضاً شأن من شؤون الطبقات الأعلى.
الحيوية على اتصال هادئ. إذا لم يرسل أي من الطرفين بيانات لفترة طويلة، فإن الاتصال لا يزال مفتوحاً من الناحية الفنية لكنه لا يستطيع اكتشاف أن الطرف الآخر قد تعطّل أو اختفى. ويمكن تمكين تحقيقات keepalive على المقبس لمعالجة ذلك عندما يكون مهماً.
9.10.4. متى تستخدم TCP¶
إن TCP هو الجواب الصحيح لأي محادثة تقريباً تنطبق عليها صورة "يفتح العميل اتصالاً بخادم، فيتبادلان بعض البايتات، ثم يُغلق الاتصال عند الانتهاء". فطلبات HTTP و HTTPS، وجلسات SSH، واستعلامات قواعد البيانات، ونقل الملفات، ورفع الصور -- كلها تجري عبر TCP.
لا تلجأ إلى UDP إلا عندما لا تنطبق على المحادثة تلك الصورة: الرسائل المستقلة المكتفية بذاتها حيث يكون الفقدان مقبولاً، أو حركة البث المتعدد، أو مزامنة الوقت، أو عمليات البحث عن الأسماء، أو الحالات الشديدة الحساسية لزمن الاستجابة حيث تكون تكلفة المصافحة باهظة.
بوجود المنافذ و UDP و TCP كلها على الطاولة، تكون قصة طبقة النقل قد اكتملت. أما واجهة Python البرمجية التي تكشف كليهما فهي في الصفحة التالية: كائنات المقابس.