سبب فشل اتصال العميل

عادةً ما يكون هناك نوعان من أخطاء فشل الاتصال للعميل، connection refuse و connection timeout.

connection refuse (رفض الاتصال)

عادةً ما يكون السبب في ذلك:

  1. العميل قد قام بتوجيه الاتصال إلى منفذ خاطئ.
  2. العميل قد قام بتوجيه الاتصال إلى اسم مضيف أو عنوان IP خاطئ.
  3. إذا استخدم العميل الاتصال بالاسم المضيف، قد يكون الاسم المضيف يشير إلى عنوان IP خاطئ للخادم.
  4. الخادم يستخدم خدمة التوزيع المحتوى أو خدمة الوكيل للتسريع، مما يؤدي إلى عدم تطابق عنوان IP الفعلي للاتصال مع العنوان المتوقع.
  5. الخادم غير مشغل أو لا يتم استماع إلى المنفذ.
  6. الاستخدام الخاص ببرامج الوكيل الشبكي.
  7. عنوان الاستماع للخادم لا يتوافق مع عنوان الوصول. على سبيل المثال، إذا كان الخادم يستمع على 127.0.0.1، سوف يكون العميل قادرًا فقط على الاتصال عبر 127.0.0.1 ولا يمكنه الاتصال عبر عنوان IP المحلية أو العامة. يُفضل تعيين عنوان الاستماع إلى 0.0.0.0 ليكون بذلك يمكن للجهاز المحلي والشبكة المحلية والشبكة العامة الاتصال.

connection timeout (انتهاء مهلة الاتصال)

عادةً ما يكون السبب في ذلك:

  1. جدار الحماية على الخادم يمنع الاتصال، يمكن تعطيل جدار الحماية مؤقتًا للاختبار.
  2. إذا كانت هناك خادم سحابي، فإن مجموعة الأمان قد تمنع إقامة الاتصال، ويجب فتح المنفذ المقابل في لوحة التحكم.
  3. إذا كان في استخدام لوحة التحكم مثل باوتا، فيجب فتح المنفذ المقابل في باوتا.
  4. الخادم غير موجود أو غير مشغل.
  5. إذا استخدم العميل الاتصال بالاسم المضيف، فقد يكون الاسم المضيف يشير إلى عنوان IP خاطئ للخادم.
  6. عندما يكون عنوان IP الذي يتم الوصول إليه من قبل العميل هو عنوان IP داخلي للخادم، وليس هناك اتصال بين العميل والخادم في نفس الشبكة المحلية.

cannot assign requested address (لا يمكن تخصيص العنوان المطلوب)

كعميل، كل مرة يتم فيها إقامة الاتصال يجب أن يقوم بتوجيه منفذ مؤقت محلي، تكون هناك حوالي 2-3 آلاف منفذ مؤقت متاحة افتراضيًا على الخادم. إذا تجاوز عدد الاتصالات التي يتم توجيهها إلى الخادم هذه القيمة، فلن يتمكن من تخصيص منفذ متاح، وسيرتفع الخطأ.
يمكن زيادة عدد منافذ المؤقت المحلية عن طريق تعديل معلمات النواة في /etc/sysctl.conf، على سبيل المثال، يمكن تعيين نطاق المنفذ المؤقت المحلي إلى 10000 65535 (ما يعادل زيادة عدد المنافذ المتاحة إلى 65535)، ويمكن تطبيق التغييرات من خلال تشغيل sysctl -p.
بالإضافة إلى ذلك، بعد انقطاع الاتصال، يظل توجيه المنفذ المحلي في حالة انتظار الوقت (TIME_WAIT) لفترة معينة، مما يعني أن إقامة كمية كبيرة من الاتصالات القصيرة (أكثر من 2-3 آلاف) في وقت قصير قد يتسبب في ظهور خطأ "Cannot assign requested address". في حالات من هذا النوع، يمكن حل المشكلة عن طريق ضبط سرعة استرداد TIME_WAIT في النواة، يمكن الرجوع إلى تحسين النواة.

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

أخطاء أخرى

إذا حُدثت أخطاء أخرى بخلاف connection refuse و connection timeout، فعادة ما يكون السبب في ذلك:

1. العميل يستخدم بروتوكول الاتصال غير المتوافق مع الخادم.
على سبيل المثال، إذا كان الخادم يستخدم بروتوكول الاتصال HTTP، فإن استخدام العميل لبروتوكول الاتصال WebSocket لن يكون ممكنًا. إذا استخدم العميل بروتوكول الاتصال WebSocket للاتصال، فإن الخادم يجب أن يستخدم أيضًا بروتوكول الاتصال WebSocket. إذا كان الخادم يستخدم بروتوكول الاتصال HTTP، فيجب على العميل استخدام بروتوكول الاتصال HTTP.

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

أمثلة شائعة للأخطاء الناتجة عن عدم توافق البروتوكولات:

فشل الاتصال عبر WebSocket 'ws://xxx.com:xx/' بسبب خطأ أثناء مصافحة WebSocket: كود استجابة غير متوقع: xxx

فشل الاتصال عبر WebSocket 'ws://xxx.com:xx/' بسبب خطأ أثناء مصافحة WebSocket: net::ERR_INVALID_HTTP_RESPONSE

طريقة الحل:
من خلال الأخطاء المذكورة أعلاه، يمكن أن نعرف أن العميل يستخدم اتصال WebSocket. وبالتالي، يجب على الخادم أيضًا استخدام اتصال WebSocket للاتصال. يجب على جزء الاستماع في الخادم أن يحدد بروتوكول الاتصال WebSocket للتواصل، كما في المثال التالي:

إذا كان gatewayWorker، فيمكن أن يكون الجزء الخاص بالاستماع كالتالي:

// بروتوكول الاتصال WebSocket، بهذا الشكل يمكن للعميل الاتصال عبر ws://...xxxx.
$gateway = new Gateway('websocket://0.0.0.0:xxxx');

إذا كان Workerman، فيمكن أن يكون كالتالي:

// بروتوكول الاتصال WebSocket، بهذا الشكل يمكن للعميل الاتصال عبر ws://...xxxx.
$worker = new Worker('websocket://0.0.0.0:xxxx');