سؤال كيف يتم إغلاق مأخذ توصيل قسريًا في TIME_WAIT؟


أركض برنامج معين على لينكس التي تعطل في بعض الأحيان. إذا قمت بفتحه بسرعة بعد ذلك ، فإنه يستمع على مأخذ 49201 بدلا من 49200 كما فعلت في المرة الأولى. يكشف netstat أن 49200 في حالة TIME_WAIT.

هل هناك برنامج يمكنك تشغيله فورًا لفرض مأخذ التوصيل هذا خارج حالة TIME_WAIT؟


109
2017-09-03 12:57


الأصل


إذا كنت هنا بسبب "كثير جدا TIME_WAIT على الخادم "، مجرد تخطي من خلال الإجابات الثلاثة الأولى التي تتجنب السؤال بدلاً من الإجابة عليه. - Pacerier


الأجوبة:


/etc/init.d/networking restart

اسمحوا لي أن أتوسع. تم تصميم بروتوكول التحكم في الإرسال (TCP) ليكون بروتوكول نقل بيانات ثنائي الاتجاه وموثوق به وموثوق بين نقطتي النهاية (البرامج). في هذا السياق ، يعني المصطلح موثوق به أنه سيقوم بإعادة إرسال الحزم إذا ضاع في الوسط. يضمن TCP الموثوقية عن طريق إرسال الحزم Acknowledgement (ACK) مرة أخرى للحصول على واحد أو مجموعة من الحزم المتلقاة من النظير.

وهذا ينطبق على إشارات التحكم مثل طلب / استجابة الإنهاء. RFC 793 يحدد حالة TIME-WAIT على النحو التالي:

TIME-WAIT - يمثل انتظار   ما يكفي من الوقت لتمرير للتأكد       تلقى TCP بعيد الاعتراف من اتصاله       طلب إنهاء.

انظر الشكل التالي لحالة TCP: alt text

TCP هو بروتوكول اتصال ثنائي الاتجاه ، لذلك عندما يتم تأسيس الاتصال ، لا يوجد فرق بين العميل والخادم. أيضا ، إما يمكن للمرء أن يدعو إنهاء ، وكلا النظراء بحاجة إلى الاتفاق على إغلاق لإغلاق اتصال TCP ثابت تماما.

دعونا ندعو أول واحد للاتصال الاقالات كما أقرب نشطة ، والأخرى النظير السلبي أقرب. عندما يرسل النشط أقرب FIN ، تنتقل الولاية إلى FIN-WAIT-1. ثم يتلقى ACK لـ FIN المرسلة والحالة تذهب إلى FIN-WAIT-2. بمجرد أن يتلقى FIN أيضًا من السالب ، فإن النشط أقرب يرسل ACK إلى FIN وتنتقل الحالة إلى TIME-WAIT. في حالة عدم تلقي أقرب سلبي ACK إلى FIN الثاني ، فسوف يقوم بإعادة إرسال حزمة FIN.

RFC 793 تعيين TIME-OUT ليكون ضعف مدة مقطع الحد الأقصى ، أو 2MSL. نظرًا لأن MSL ، الحد الأقصى للوقت الذي يمكن للحزمة التجول فيه عبر الإنترنت ، يتم تعيينه إلى دقيقتين ، 2MSL هو 4 دقائق. نظرًا لعدم وجود ACK إلى ACK ، لا يمكن للأقرب النشط فعل أي شيء سوى الانتظار لمدة 4 دقائق إذا تم الالتزام ببروتوكول TCP / IP بشكل صحيح ، فقط في حالة عدم تلقي المرسل السلبي ACK إلى FIN (نظريًا) .

في الواقع ، ربما تكون الحزم المفقودة نادرة ، ونادرة جدًا إذا حدث كل ذلك داخل الشبكة المحلية أو داخل جهاز واحد.

للإجابة على السؤال حرفيا ، كيف غصبا إغلاق مقبس في TIME_WAIT ؟، سأظل ملتصقًا بإجابتي الأصلية:

/etc/init.d/networking restart

من الناحية العملية ، أود أن البرنامج عليه لذلك يتجاهل حالة TIME-WAIT باستخدام خيار SO_REUSEADDR كما ذكر WMR. ما الذي تفعله SO_REUSEADDR بالضبط؟

يخبر خيار مأخذ التوصيل هذا kernel   هذا حتى لو كان هذا المنفذ مشغول (في
  حالة TIME_WAIT) ، امض قدما و   إعادة استخدامها على أي حال. إذا كانت مشغولة ، ولكن   مع دولة أخرى ، سوف تحصل عليها   عنوان بالفعل في استخدام الخطأ. هذا   مفيد إذا تم إغلاق الخادم الخاص بك   إلى أسفل ، ثم إعادة التشغيل على الفور   بينما مآخذ لا تزال نشطة في   ميناء. يجب أن تكون على علم أنه إذا   أي بيانات غير متوقعة تأتي ، قد يكون   تخلط بين الخادم الخاص بك ، ولكن في حين أن هذا   ممكن ، ليس من المرجح.


139
2017-09-03 13:11



إجابة عظيمة ، لكن ليس الإجابة الصحيحة على سؤاله. ستعمل إعادة تشغيل الشبكات ، لكن عندها ستتم إعادة التشغيل ، لذا لا يمكن أن يكون هذا صحيحًا. - Chris Huang-Leaver
Chris Huang-Leaver ، السؤال هو "هل هناك برنامج يمكنك تشغيله على الفور لإجبار هذا المقبس على الخروج من حالة TIME_WAIT؟" إذا كان يمكن اعتبار إعادة التشغيل تشغيل برنامج ، فإنه سيكون أيضا إجابة صحيحة. لماذا تعتقد أن هذا لا يمكن أن يكون صحيحًا؟ - Eugene Yokota
لدى WMR الإجابة الأكثر فائدة (وهو ما أفعله عندما أواجه هذا النوع من المشكلات). إن إعادة تشغيل الشبكة أمر غاية في الصعوبة بحيث لا يكون الحل ، وقد يستغرق وقتًا أطول من مجرد انتظار المهلة. الإجابة الصحيحة على سؤاله هي "لا" ، لكن SO لن يسمح لك بكتابة إجابتين حرفين :-) - Chris Huang-Leaver
حسنًا ، في المرة القادمة التي تتوقف فيها بعض العمليات على SIGTERM سأقوم بتحطيم جهاز الكمبيوتر الخاص بي بدلاً من إصلاحه. - Longpoke


لا أعرف ما إذا كان لديك رمز المصدر لهذا البرنامج المحدد الذي تعمل عليه ، ولكن إذا كان الأمر كذلك ، يمكنك تعيين SO_REUSEADDR عبر setsockopt(2) والذي يسمح لك بالربط على نفس العنوان المحلي حتى إذا كان المقبس في حالة TIME_WAIT (إلا إذا كان هذا المقبس يستمع بشكل نشط ، انظر socket(7)).

لمزيد من المعلومات حول حالة TIME_WAIT ، راجع يونكس مأخذ أسئلة وأجوبة.


50
2017-09-03 13:17



لكنني لم أحصل على خطأ ملزمة بالفعل. عندما أقوم بتنفيذ البرنامج مرة أخرى فإنه يستمع في آخر (123456) أيضا أستطيع أن أرى أن النظام يعرض TIME_WAIT لهذا المنفذ ولكن لا يزال يمكنني الاتصال. لماذا ا؟ - Jayapal Chandran
حتى مع SO_REUSEADDR ، لا يزال من الممكن الحصول على خطأ "العنوان قيد الاستخدام بالفعل". لمزيد من التفاصيل ، يرجى الرجوع إلى hea-www.harvard.edu/~fine/Tech/addrinuse.html. - Jingguo Yao
WMR SO_REUSEADDR لا "إغلاق" مأخذ توصيل. انها مجرد تمكنك من إعادة استخدام تلك التي تم فتحها بالفعل. وبالتالي فإن السؤال لا يزال "كيفية إغلاق مأخذ في بالقوة في TIME_WAIT؟ " - Pacerier


بقدر ما أعرف لا توجد وسيلة لإغلاق المقبس عنوة خارج كتابة معالج إشارة أفضل في البرنامج الخاص بك ، ولكن هناك ملف / proc الذي يتحكم في المدة التي تستغرقها المهلة. الملف هو

/proc/sys/net/ipv4/tcp_tw_recycle

ويمكنك ضبط المهلة لمدة ثانية واحدة عن طريق القيام بذلك:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 

ومع ذلك، هذه الصفحة يحتوي على تحذير حول مشكلات الوثوقية المحتملة عند تعيين هذا المتغير.

هناك أيضا ملف ذات الصلة

/proc/sys/net/ipv4/tcp_tw_reuse

يتحكم في ما إذا كان يمكن إعادة استخدام مآخذ TIME_WAIT (من المفترض عدم وجود أي مهلة).

بالمناسبة ، يحذرك توثيق النواة من تغيير أي من هذه القيم دون "نصيحة / طلبات من الخبراء التقنيين". أنا لست كذلك.

يجب كتابة البرنامج لمحاولة ربط المنفذ 49200 ومن ثم زيادة 1 إذا كان المنفذ قيد الاستخدام بالفعل. لذلك ، إذا كان لديك التحكم في التعليمات البرمجية المصدر ، فيمكنك تغيير هذا السلوك للانتظار بضع ثوانٍ وحاول مرة أخرى على نفس المنفذ ، بدلاً من الزيادة.


32
2017-09-03 13:24



أعتقد أن المثالين الثانيين يجب أن يكونا s / rw / tw / I'd ، ولكن لا يوجد ما يكفي من rep.
مأخوذة من وثائق النواة: الحذر. يمكن أن يتسبب كل من tcp_tw_recycle و tcp_tw_reuse في حدوث مشكلات. يجب عدم تمكين أي منهما دون فهم طوبولوجيا الشبكة بين العقدة (العقدة) التي تستخدمها أو تستخدمها العقدة حيث يتم تمكين المعلمة. قد تبدأ الاتصالات التي تمر عبر العقد التي تدرك حالات اتصال TCP ، مثل جدار الحماية أو NAT أو موازن التحميل بإسقاط الإطارات بسبب الإعداد. سوف تصبح المشكلة مرئية عند وجود عدد كبير من الاتصالات كافية.
وضعه ل 1 يعمل للعلاقات المستقبلية ، ولكن ماذا عن تلك الحالية التي تم فتحها بالفعل؟ - Pacerier


في الواقع هناك طريقة لقتل اتصال - killcx. يدعون أنها تعمل في أي حالة من الاتصال (التي لم تتحقق منها). تحتاج إلى معرفة الواجهة التي يحدث بها الاتصال ، يبدو أنها تفترض eth0 بشكل افتراضي.

استكمال: حل آخر هو قاطعة الذي يأتي في بعض مستودعات linux distros.


16
2017-10-30 17:32



شكر! هذه الأداة تعمل عظيم! أنقذني من الاضطرار إلى إعادة تشغيل مهمة طويلة. - Zanson


خيار آخر هو استخدام خيار SO_LINGER مع انتهاء مهلة 0. بهذه الطريقة ، عند إغلاق المقبس يتم إغلاقه قسريًا ، وإرسال RST بدلاً من الدخول في سلوك إغلاق FIN / ACK. سيؤدي هذا إلى تجنب حالة TIME_WAIT ، وقد يكون أكثر ملاءمة لبعض الاستخدامات.


3
2018-06-10 22:33



كما يفقد أي بيانات خارجية لا تزال قيد النقل ، وقد يتسبب في حدوث خطأ في الطرف الآخر. لا ينصح. - user207421
EJP فشل في وقت مبكر هو دائما تقريبا الدعوة الصحيحة. لا يمكن الاعتماد على الشبكات ، وسيؤدي القتال إلى إبطاء الأمور. لا يمكن أن يفترض تطبيق محطم أن أي بيانات قد أخرجته بأمان. - Tobu
في الواقع ، أود أن أوصي بذلك في أي يوم عندما تكون نقطة النهاية الأخرى عبارة عن عبّارة حافلة صناعية مدمجة وعائمة ، تقوم بتنفيذ النقل الموثوق به طبقة التطبيق الخاصة بها عبر بروتوكول TCP ، حيث يمنع النقل المذكور الاتصال من الإغلاق ما لم يتلقى RST وبالتالي يمتلئ حد الاتصال على تلك العبارة. هناك. لقد أعطيتك مثالاً محددًا للغاية وحقيقيًا جدًا ، للأسف ، يتطلب اللجوء إلى الاختراقات من هذا القبيل. - andyn
Tobu Networking غير موثوقة ، ولكن TCP يحاول أن يكون ، وجعل هذا أسوأ لا يشكل أي شيء أفضل ، وترك TCP يقوم بعمله لا يشكل "القتال" أي شيء. - user207421


قد يكون الحل البديل هو الحصول على بعض البرامج الموثوقة للبروكسي أو المنفذ التي تستمع على المنفذ 49200 ، ثم إعادة توجيه الاتصال إلى أحد الأمثلة العديدة لبرنامجك الأقل موثوقية باستخدام منافذ مختلفة ... ننبذ HAPROXY إلى الذهن.

وبالمناسبة فإن المنفذ الذي تتصل به مرتفع للغاية. يمكنك محاولة استخدام واحدة غير مستخدمة فقط فوق النطاق 0-1024. من المحتمل أن يستخدم نظامك رقم منفذ أقل كمنفذ سريع الزوال.


2
2017-08-21 20:28





TIME_WAIT هي المشكلة الأكثر شيوعًا في بنية خادم عميل برمجة مأخذ التوصيل. انتظر لبضع ثوان في المحاولة بشكل دوري هو الحل الأفضل لذلك. لتطبيقات في الوقت الحقيقي يحتاجون إلى الخادم يجب الحصول على ما يصل على الفور هناك خيار SO_REUSEADDR لهم.


0
2017-10-13 19:07