سؤال

حسنًا، لدي استثناء غريب من الكود الخاص بي والذي كان يضايقني منذ زمن طويل.

System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall
   at System.Net.Sockets.Socket.Accept()
   at System.Net.Sockets.TcpListener.AcceptTcpClient()

MSDN ليس مفيدًا جدًا في هذا: http://msdn.microsoft.com/en-us/library/ms741547(VS.85).aspx وأنا لا أعرف حتى كيف أبدأ في استكشاف هذه المشكلة وإصلاحها.يتم طرحه 4 أو 5 مرات فقط في اليوم، ولا يتم إطلاقه في بيئة الاختبار الخاصة بنا.فقط في مواقع الإنتاج، وفي جميع مواقع الإنتاج.

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

يتم تشغيل الكود في سلسلة منفصلة في الخلفية، وتبدأ الطريقة:

public virtual void Startup()
    {
     TcpListener serverSocket= new TcpListener(new IPEndPoint(bindAddress, port));    
        serverSocket.Start();

ثم أقوم بتشغيل حلقة لوضع كافة الاتصالات الجديدة كوظائف في تجمع مؤشرات ترابط منفصل.يصبح الأمر أكثر تعقيدًا بسبب بنية التطبيق، ولكن في الأساس:

   while (( socket = serverSocket.AcceptTcpClient()) !=null) //Funny exception here
    {
         connectionHandler = new ConnectionHandler(socket, mappingStrategy);
         pool.AddJob(connectionHandler);
    }
  }

ومن هناك، pool لديه خيوط خاصة به تعتني بكل وظيفة في موضوعه الخاص، بشكل منفصل.

ما أفهمه هو أن AcceptTcpClient() عبارة عن مكالمة حظر، وأن Winsock بطريقة ما يطلب من مؤشر الترابط التوقف عن الحظر ومواصلة التنفيذ..لكن لماذا؟وماذا يفترض بي أن أفعل؟مجرد التقاط الاستثناء وتجاهله؟


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

وبدلاً من ذلك، هل يمكن أن يكون هذا ببساطة هو إغلاق خادم IIS لتطبيقي، وبالتالي إلغاء جميع سلاسل العمليات الخلفية وطرق الحظر الخاصة بي؟

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

المحلول

هل من الممكن أن يتم إغلاق serverSocket من موضوع آخر؟سيؤدي ذلك إلى هذا الاستثناء.

نصائح أخرى

هذا هو الحل المثالي الخاص بي لتجنب WSAcancelblablabla:حدد مؤشر الترابط الخاص بك على أنه عالمي ثم يمكنك استخدام طريقة الاستدعاء مثل هذا:

private void closinginvoker(string dummy)
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action<string>(closinginvoker), new object[] { dummy });
            return;
        }
        t_listen.Abort();
        client_flag = true;
        c_idle.Close();
        listener1.Stop();
    }

بعد استدعائه، أغلق سلسلة الرسائل أولاً ثم علامة الحلقة الأبدية حتى تمنع المزيد من الانتظار (إذا كان لديك)، ثم أغلق tcpclient ثم أوقف المستمع.

يمكن أن يحدث هذا على serverSocket.Stop().الذي اتصلت به كلما Dispose كان يسمى.

إليك كيف يبدو التعامل مع الاستثناء الخاص بي لسلسلة الاستماع:

try
{
    //...
}
catch (SocketException socketEx)
{    
    if (_disposed)
        ar.SetAsCompleted(null, false); //exception because listener stopped (disposed), ignore exception
    else
        ar.SetAsCompleted(socketEx, false);
}

الآن ما حدث هو أنه في كثير من الأحيان كان الاستثناء يحدث من قبل _disposed تم ضبطه على صحيح.لذلك كان الحل بالنسبة لي هو جعل كل شيء آمنًا.

نفس الشيء هنا!لكنني اكتشفت أن جهاز الاستقبال على "جانب الخادم" قد تم غمره من العملاء!(في حالتي، هناك مجموعة من ماسحات RFID، الذين استمروا في إرسال بريد عشوائي إلى TagCode، بدلاً من التوقف عن الإرسال حتى وصول TagCode التالي)

لقد ساعد في رفع جهاز الاستقبال العازل وإعادة تكوين الماسحات الضوئية...

لقد رأيت هذا الاستثناء مؤخرًا عند استخدام HttpWebRequest لوضع ملف كبير وتم تجاوز فترة المهلة.

سيؤدي استخدام الكود التالي طالما أن وقت التحميل > 3 ثوانٍ إلى حدوث هذا الخطأ بقدر ما أستطيع رؤيته.

string path = "Reasonably large file.dat";
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
System.Net.HttpWebRequest req = (HttpWebRequest)System.Net.HttpWebRequest.Create("Some URL");
req.Method = "PUT";
req.Timeout = 3000; //3 seconds, small timeout to demonstrate
long length = new System.IO.FileInfo(path).Length;
using (FileStream input = File.OpenRead(path))
{
    using (Stream output = req.GetRequestStream())
    {
        long remaining = length;
        int bytesRead = 0;
        while ((bytesRead = input.Read(buffer, 0, (int)Math.Min(remaining, (decimal)bufferSize))) > 0)
        {
            output.Write(buffer, 0, bytesRead);
            remaining -= bytesRead;
        }
        output.Close();
    }
input.Close();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top