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

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

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

عادةً ما تكون الأسباب كما يلي:

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

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

عادةً ما تكون الأسباب كما يلي:

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

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

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

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

أخطاء أخرى

إذا لم يكن الخطأ هو 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

حلول:
من خلال الأخطاء المذكورة، يتضح أن العميل يستخدم ws للاتصال ببروتوكول 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');