TCP المقبس خادم يبني CLOSE_WAITs أحيانا على مر الزمن حتى غير صالحة للعمل

StackOverflow https://stackoverflow.com/questions/679643

سؤال

ونأمل أن نجد المساعدة لنا ونحن صولا إلى تحقيق يمكن أن تذهب!

لقد حصلت بسيط الخادم مأخذ غير متزامن مكتوب في C # يقبل الاتصالات من تطبيق ويب ASP.NET، يتم إرسال رسالة، يقوم بعض المعالجة (عادة ضد DB ولكن أنظمة أخرى أيضا) ومن ثم يرسل استجابة إلى الوراء إلى العميل. العميل هو المسؤول عن إغلاق الاتصال.

لقد تم وجود قضايا حيث إذا كان النظام تحت الحمل الثقيل على مدى فترة طويلة من الزمن (أيام عادة)، ومآخذ CLOSE_WAIT تتراكم في المربع خادم (-A NETSTAT) إلى حد أن عملية لن يقبل أي اتصالات أخرى. عند هذه النقطة علينا أن ترتد هذه العملية، ومن تشغيله مرة أخرى.

لقد حاولت تشغيل بعض اختبارات الحمل من تطبيق ASP.NET جهدنا لمحاولة تكرار المشكلة (لاستنتاج بعض المسألة من التعليمات البرمجية لم يكن ممكنا). نحن نعتقد أننا تمكنا هذا وانتهى مع يريشارك حزمة أثر القضية يظهر نفسه على أنه SocketException في سجلات خادم مقبس ل:

<اقتباس فقرة>   

System.Net.Sockets.SocketException: تم إغلاق اتصال موجود بالقوة المضيف البعيد   في System.Net.Sockets.Socket.BeginSend (بايت [] العازلة، Int32 الإزاحة، Int32 حجم، SocketFlags socketFlags، AsyncCallback الاستدعاء، كائن حالة)

ولقد حاول إعادة إنشاء المشكلة من تتبع حزمة كعملية مترابطة واحد يتحدث مباشرة إلى خادم المقبس (باستخدام نفس رمز التطبيق ASP.NET لا) وغير قادر.

حصل

لقد أي شخص أي اقتراحات من الأشياء القادمة في محاولة، لفحص أو الأشياء واضحة يجوز لنا أن تفعل الخطأ؟

هل كانت مفيدة؟

المحلول

ونظرة على الرسم البياني

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

والعميل الخاص بك إغلاق الاتصال عن طريق استدعاء قريب ()، التي أرسلت FIN إلى مقبس الخادم الذي ACKed على FIN والدولة التي تغيرت الآن إلى CLOSE_WAIT، ويبقى على هذا النحو ما لم القضايا الخادم قريب () ندعو أن المقبس.

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

نصائح أخرى

إذا خادمك يجمع مآخذ CLOSE_WAIT ثم انها ليست إغلاق فتحتها عند اتصال كاملة. إذا كنت تأخذ نظرة على الرسم التخطيطي للدولة في التعليق إلى آخر كريس سترى أن التحولات CLOSE_WAIT إلى LAST_ACK بمجرد إغلاق مأخذ التوصيل وتم إرسال FIN.

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

قد يكون إصدار قراءة جديدة في الاستدعاء من القراءة التي ترجع 0 مشيرا إلى أن العميل قد أغلقت وهذا قد تسبب لك مشاكل؟

<اقتباس فقرة>   

والعميل هو المسؤول عن إغلاق الاتصال.

وكل من العميل والخادم يجب إغلاق وإيقاف المقبس. إما العميل لا الانتهاء من وثيقة (غير المحتمل - منذ أن كنت قد حان finalizer تشغيل) أو الملقم لا اغلاق المقبس (على الأرجح)

.
using (Socket s = new Socket(/* */)) {
  /* Do stuff */
  s.Shutdown(SocketShutdown.Both);
  s.Close();
}

وأنت لا ينبغي ترك مسؤولية إغلاق مآخذ TCP فقط ما يصل الى العميل. ماذا يحدث إذا عملية العميل / تعطل الجهاز؟

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

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

وهذا إصدار أمر وثيق، وببساطة يقول المستمع (الخادم) أن الاتصال يجب أن يغلق أسفل.

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

والمقصود

وCLOSE_WAIT لتسكع لفترة من الوقت بعد إغلاق مأخذ، لمنع نفس العدد مأخذ واستقبال الحزم من اتصال القديم باستخدام إعادة. هذا وسوف تعطي إلا لك الحزن إذا كنت فتح وإغلاق عدد huuuuge من مآخذ بسرعة حقا.

وتحرير - يجب أن يكون TIME_WAIT، لا CLOSE_WAIT أعلى

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top