لا يمكن إعادة ربط مأخذ توصيل بمجموعة IP/Port موجودة

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

  •  09-06-2019
  •  | 
  •  

سؤال

تحياتي، أحاول إيجاد طريقة "لإلغاء ربط" مأخذ توصيل من مجموعة IP/Port معينة.يبدو الكود الكاذب الخاص بي كما يلي:

ClassA a = new ClassA(); //(class A  instantiates socket and binds it to 127.0.0.1:4567) 
//do something 
//...much later, a has been garbage-collected away.
ClassA aa = new ClassA(); //crash here.

عند هذه النقطة، أبلغني .Net أنني حصلت بالفعل على مقبس مرتبط بـ 127.0.0.1:4567، وهذا صحيح من الناحية الفنية.لكن بغض النظر عن الكود الذي أضعه في أداة تدمير ClassA، أو بغض النظر عن الوظائف التي أستدعيها على المقبس (لقد جربت .Close() و .Disconnect(true))، يظل المقبس مرتبطًا بكل فخر بـ 127.0.0.1:4567.ماذا أفعل حتى أتمكن من "فك ربط" المقبس؟


يحرر:أنا لا أعتمد فقط على جمع البيانات المهملة (على الرغم من أنني جربت هذا النهج أيضًا).لقد حاولت الاتصال بـ a.Close() أو a.Disconnect() وبعد ذلك فقط قمت بإنشاء مثيل aa;هذا لا يحل المشكلة.


يحرر:لقد حاولت أيضًا تنفيذ IDisposable، لكن الكود لم يصل إلى هناك بدون استدعاء الطريقة (والتي كانت مكافئة للمحاولات السابقة، حيث ستحاول الطريقة ببساطة .Close و .Disconnect).دعني أحاول الاتصال. تخلص مباشرة وأعود إليك.


تحرير (الكثير من التعديلات والاعتذارات):تنفيذ IDisposable واستدعاء a.Dispose() من حيث يفقد "a" النطاق لا يعمل - لا يزال يتعين على تطبيق Dispose الخاص بي استدعاء إما .Close أو .Disconnect(true) (أو .Shutdown(كلاهما)) ولكن لا شيء من تلك غير المقيد المقبس.

سيكون موضع تقدير أي مساعدة!

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

المحلول

(هذا هو ما جعل كل شيء يعمل لصالحي أخيرًا)

تأكد من أن كل مقبس يتصل به المقبس الموجود في A

socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress, true);

تعيين عند البدء.

نصائح أخرى

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

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

لا يضمن لك جامع البيانات المهملة أن المقبس سيتم إغلاقه على الإطلاق.للحصول على مثال كامل اقرأ هذا مثال MSDN.

النقطة الأساسية هي الاتصال فعليًا Socket.Close() في أسرع وقت ممكن.على سبيل المثال، يمكن تنفيذ ClassA يمكن التخلص منه واستخدامها مثل هذا:

using (ClassA a = new ClassA()) 
{
    // code goes here
}
// 'a' is now disposed and the socket is closed

يقوم جامع البيانات المهملة بتشغيل أداة الإنهاء للكائن في وقت غير محدد.يمكنك تنفيذ واجهة IDisposable واستدعاء الأسلوب Dispose() قبل أن يفقد الكائن النطاق - أو السماح لعبارة الاستخدام بالقيام بذلك نيابةً عنك.

يرى http://msdn.microsoft.com/en-us/library/system.idisposable.aspx و http://msdn.microsoft.com/en-us/library/yh598w02.aspx

يحرر:يعمل بشكل جيد بالنسبة لي

using System;
using System.Net.Sockets;
using System.Net;

namespace ConsoleApplication1
{
    class Program
    {
        class ClassA : IDisposable
        {
            protected Socket s;
            public ClassA()
            {
                s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                s.Bind(new IPEndPoint(IPAddress.Any, 5678));
            }

            public void Dispose()
            {
                s.Close();
            }
        }

        static void Main(string[] args)
        {
            using(ClassA a=new ClassA()) {
            }
            using (ClassA b = new ClassA())
            {
            }
        }
    }
}

الحل الأفضل هو إعادة محاولة ربط المقبس عدة مرات (2-3).في المحاولة الأولى، إذا فشلت، فقد وجدت أنه سيتم إغلاق المقبس الأصلي بشكل صحيح (وبشكل دائم).

هث،

_NT

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