TCP مقابل UDP للمطورين — متى يهم الاتصال بالبروتوكول
توقف عن اعتبار TCP وUDP خيارات مُعادلة. إليك ما يكلفه التأكيد على الاتصال، لماذا تعمل DNS على UDP، وسبب تباطؤ لعبةك.
أنت تُطوّر لعبة متعددة اللاعبين، ويشكو اللاعبون من تأخر الاتصال. لقد قمت بتحسين كود الخادم، وقلل من استعلامات قاعدة البيانات، ونُظرت الأداء في الـ p99 بشكل جيد. المشكلة بسيطة جدًا: تستخدمين بروتوكول TCP. هذا هو السبب في التأخير.
البروتوكولان TCP وUDP ليسا مجرد مربعين في قائمة البروتوكولات — يمثلان مواقف جوهرية مختلفة حول ما سيقوم به الشبكة. اختيار خاطئ لا يُفقد فقط أداءً، بل يغيّر طبيعة الفشل عندما تحدث الأشياء.
المُستند الذي يُقدّمه TCP
يُعدّ TCP لك تدفقًا موثوقًا ومرتبًا للبُعد. إذا فقدت حزمة، سيُعيد TCP إرسالها. إذا وصلت الحزم بشكل غير منسق، سيُعيد TCP ترتيبها. يرى تطبيقك بيانات منظمة وسلسة في كل مرة.
هذا التأكيد يُكلفك ثلاث أشياء:
- تأخير التبادل الأولي — يتطلب TCP تبادلًا ثلاثيًا قبل أن يُرسل أي بُعد من بيانات التطبيق. على شبكة بـ 50 مللي ثانية، تُستهلك 150 مللي ثانية قبل أن يبدأ طلبك حتى أول مرة.
- إغلاق الرأس (Head-of-line blocking) — هذا هو السبب الذي يُقتل فيه الألعاب. إذا فقدت الحزمة #5، فإن TCP يُوقف الحزم #6، #7، و#8 في مخزن ينتظر أن تصل الحزمة #5 مجددًا. يُصبح التدفق مُحَدّد. يُبقى تحديث موضع اللاعب من 100 مللي ثانية في مخزن بينما يُعالج الشبكة المشكلة.
- أحمال التحكم في التكدس — يُقلل بروتوكول TCP للحد من معدل الإرسال عند اكتشاف فقدان. على شبكة مُتضررة، هذا يعني أن TCP يقلل من سرعة الإرسال في اللحظة التي يشعر فيها المستخدم بالتأخير — وهي اللحظة التي يشعر فيها المستخدم بالتأخير أكثر.
ما يُقدّمه UDP فعليًا
يُرسل UDP حزمة وينظر إلى الوراء. لا تبادل، لا تأكيد، لا إعادة إرسال. إذا فقدت حزمة، فهي مفقودة. يحصل المُستقبل على ما يصل إليه، في أي ترتيب يصل إليه.
هذا ليس عيبًا — إنه هو الهدف. عندما تحتاج إلى تأخير منخفض أكثر من ضمان التوصيل، يسمح لك UDP باتخاذ هذا التبادل بشكل صريح. يُنتقل منطق الموثوقية إلى طبقة التطبيق، حيث يمكنك اتخاذ قرارات أكثر ذكاءً حول ما يحتاج إلى إعادة إرساله.
في لعبة، فإن تحديث موضع اللاعب من 50 مللي ثانية ليس له قيمة — ترغب في التحديث الحالي. مع TCP، سترى تدفقًا مُحَدّدًا ويُنتظر. مع UDP، تُرسل الحالة الجديدة وتجاهل أي شيء قديم. يكون التجربة أكثر سلاسة حتى في حالة فقدان حزم أكثر.
مقارنة TCP وUDP: ما يهم حقًا
| ملكية | TCP | UDP |
|---|---|---|
| إعداد الاتصال | تبادل ثلاثي (يُضيف 1.5× RTT قبل أول بُعد) | لا شيء — يُرسل فورًا |
| ضمان التوصيل | نعم — إعادة إرسال عند فقدان | لا — يُرسل ويُنسى |
| ترتيب الحزم | يُفرض من قبل الطبقات | مشكلتك |
| إغلاق الرأس (Head-of-line blocking) | نعم — فقدان حزمة واحدة يُوقف التدفق | لا — كل حزمة مستقلة |
| التحكم في التكدس | مُدمج (CUBIC، BBR، إلخ) | لا شيء — اخترعها بنفسك أو تجاهلها |
| أحمال التأخير المعتادة | 150–300 مللي ثانية على اتصالات جديدة | أقل من مللي ثانية |
| استخدم حالات | HTTP/1.1، HTTP/2، قواعد البيانات، نقل الملفات، البريد الإلكتروني | DNS، الألعاب، البث الحي، HTTP/3 (QUIC) |
أين ينتمي كل بروتوكول حقًا
DNS تعمل على UDP — ولهذا هناك درس
كل استعلام DNS يُرسله تطبيقك يُرسل عبر UDP بشكل افتراضي. يناسب الطلب في حزمة واحدة، يناسب الإجابة في حزمة واحدة، ويحصل على الإجابة في جولة واحدة. لا تأخير في التبادل، ولا حالة يجب الحفاظ عليها على الخادم.
إذا كانت الإجابة كبيرة جدًا (سجلات DNSSEC، أسماء متعددة)، فإن DNS تنتقل إلى TCP. لكن الحالة الشائعة — استعلام لاسم حاسوب — هي UDP لأن التبادل الثلاثي سيستغرق أكثر من وقت الاستعلام نفسه.
يمكنك رؤية هذا السلوك في الممارسة باستخدام أداة استعلام DNS IO Tools — أدخل اسمًا وشاهد سرعة تحليل أنواع السجلات المختلفة. هذه السرعة تُظهر أن UDP تُزيل تبادل جولة كاملة من التأخير.
الألعاب: UDP هو الحل الوحيد
كل مكتبة تُستخدم في تطوير شبكات الألعاب — مثل GameNetworkingSockets من فيلا، أو EOS من إيكو، أو UTP من يونيت — تُبنى على UDP. السبب هو إغلاق الرأس.
في لعبة FPS تنافسية، تُرسل تحديثات الموضع كل 64 تيك — كل 15 مللي ثانية. إذا فقدت حزمة واحدة، ويتوقف TCP على الحزم التالية أثناء انتظار إعادة إرسالها، فإنك تُدخل 75 مللي ثانية من التوقف في اللحظة الخاطئة. مع UDP، تُرسل التحديث التالي فورًا. يُحلّل العميل على الفجوة. التجربة أكثر سلاسة.
أغلب كود الشبكة في الألعاب المبنية على UDP تُستخدم فيها موثوقية مختارة — أرقام التسلسل، طوابير الأولوية، تأكيدات مختارة — لكنها تُستخدم فقط للبيانات التي تحتاجها حقًا: رسائل المحادثة، تلقي العناصر، حالة المباريات. البيانات المتعلقة بالوضع غير موثوقة بتصميمها. تجربة قراءة قديمة أسوأ من عدم وجود قراءة.
البث الحي: يعتمد على السياق
البث الحي (مثل تويتش، بث مباريات) يستخدم بروتوكولات مبنية على UDP — مثل RTP، WebRTC، SRT — لأن فقدان بعض الأطر مقبول لكن التأخير غير مقبول. لا يمكنك تحميل 30 ثانية من مباريات حية لضمان توصيل سلس.
البث المسبق (مثل نتفليكس، يوتيوب) يستخدم في الواقع بروتوكول TCP، لأن التحميل المسبق يُخفف من التكلفة. بضع ثوانٍ من التحميل المسبق يعني أن تأخير إعادة الإرسال لا يُرى — ترى فقط توصيل سلس. لا يهم التكلفة عند مشاهدة شيء حدث قبل يوم.
يُستخدم HTTP/3 على UDP — ويُغيّر أداء الويب
يُستخدم HTTP/3 على QUIC، الذي يُستخدم على UDP. أنشأ جوجل QUIC خصيصًا لحل مشكلة إغلاق الرأس في حركة ويب من بروتوكول TCP. مع HTTP/2 على TCP، فقدان حزمة واحدة يُوقف جميع المُتسلسلات المُشاركة في الاتصال. يُنفذ QUIC تعدد المُتسلسلات على مستوى النقل مع تأكيد مستقل — فقدان حزمة واحدة يُوقف مسارًا واحدًا فقط، وليس كل المُتسلسلات.
يُدمج QUIC أيضًا التشفير في التبادل، ويقلل من إعداد الاتصال الجديد إلى جولة واحدة (0-RTT عند التبديل). على شبكات مُتضررة — مثل الاتصالات المحمولة، أو واي فاي مُزدحم — هذا تحسن مهم. في عام 2024، يدعم تقريبًا 30% من المواقع الإلكترونية HTTP/3، وتم تفعيلها بشكل افتراضي في جميع المتصفحات الرئيسية. إذا كنت تُنشر خلف Cloudflare أو مُوزع محتوى حديث، فربما تُقدم HTTP/3 دون أن تُضبطها بشكل صريح.
الجدول العملي للقرار
عند اختيار بروتوكول نقل لبروتوكول جديد أو خدمة، السؤال ليس "TCP أو UDP؟" — بل "ما هي الأخطاء التي يمكن أن أتحملها؟"
- يجب أن يصل كل بُعد، بترتيب، وإلا يفشل العملية → TCP. نقل الملفات، اتصالات قواعد البيانات، مكالمات واجهات برمجة، البريد الإلكتروني. فقدان البيانات يعني بيانات مُتضررة أو خطأ تحليل.
- التأخير مهم أكثر من ضمان التوصيل → UDP. الألعاب، البث الحي، المكالمات الصوتية، مراقبة الأجهزة. تجربة قراءة قديمة أسوأ من عدم وجود قراءة.
- تحتاج إلى كليهما، لكل رسالة → بناء على UDP مع موثوقية مختارة. يفعل هذا QUIC. يفعل هذا قناة بيانات SCTP في WebRTC. تفعل هذه المكتبات مثل ENet وGameNetworkingSockets أيضًا — لكن تطبيقها بنفسك هو عمل غير سهل ويُمكن أن يُخطئ بسهولة.
أحد الأخطاء المهمة التي يجب الإشارة إليها: الافتراض أن "الحركة الداخلية" تعني أنك يمكن أن تستخدم UDP بسهولة. فقدان الحزم داخل مجمع البيانات نادر لكنه ليس صفرًا — أخطاء الأجهزة، تكدس الشبكة تحت الحمل القصوى، مُعدّات مُخطئة. إذا أُلغيت البيانات بشكل سري، فإن الشبكة الداخلية لن تُنقذك.
الخاتمة
TCP هو الافتراض الصحيح لمعظم كود التطبيقات. إذا كنت تُرسل مكالمات واجهات برمجة، تتحدث مع قاعدة بيانات، أو تنقل ملفات، فإن التأكيدات المقدمة من TCP هي المطلوبة تمامًا، والتكاليف غير مرئية على مقياس الإنسان.
UDP هو الخيار الصحيح عندما يكون التأخير محدودًا وتطبيقك قادر على إدارة علاقته مع الموثوقية. هذه هي مجموعة محددة من المشكلات — الألعاب الحقيقية، البث الحي، البروتوكولات المخصصة — وليس تحسينًا عامًا للسرعة عندما يشعر TCP بالبطء.
الخطأ الحقيقي ليس استخدام TCP عندما يكون UDP أسرع. بل هو عدم معرفة أي بروتوكول تختاره أو لماذا، وكونك مفاجأ عندما تظهر طريقة الفشل.
تثبيت ملحقاتنا
أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع
恵 وصلت لوحة النتائج!
لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!
