สาเหตุของการเชื่อมต่อของผู้ใช้ล้มเหลว

การเชื่อมต่อที่ล้มเหลวจะมีข้อผิดพลาดสองประการคือ connection refuse และ connection timeout

connection refuse (การปฏิเสธการเชื่อมต่อ)

โดยทั่วไปเป็นเพราะ:

  1. ผู้ใช้เชื่อมต่อไปยังพอร์ตผิด
  2. ผู้ใช้เชื่อมต่อไปยังโดเมนหรือไอพีผิด
  3. หากผู้ใช้เชื่อมต่อโดยใช้ชื่อโดเมน อาจมีโดเมนชี้ไปที่ไอพีเซิร์ฟเวอร์ที่ผิด
  4. เซิร์ฟเวอร์ใช้ CDN หรือโปรกฤส์เซอร์เพิ่มเร็ว ซึ่งมีผลให้ไอพีที่เชื่อมต่อและไอพีที่คาดหวังไม่ตรงกัน
  5. เซิร์ฟเวอร์ไม่ได้เริ่มทำงานหรือพอร์ตไม่ได้รับการตรวจสอบ
  6. ใช้ซอฟต์แวร์พร็อกซี่เครือข่าย
  7. ไอพีที่เซิร์ฟเวอร์ตรวจจับและที่ที่มีการเข้าถึงไม่ได้อยู่ในช่วงที่อนุญาต ตัวอย่างเช่น หากเซิร์ฟเวอร์ตรวจสอบ 127.0.0.1 ลูกค้าจึงสามารถเชื่อมต่อได้แค่ผ่านทาง 127.0.0.1 เท่านั้น ไม่สามารถเชื่อมต่อผ่านทางไอพีโฮสต์หรือไอพีภายนอก ขอแนะนำให้ตั้งค่าที่อยู่ที่ฟังและเป็น 0.0.0.0 เพื่อทำให้เครื่องที่อยู่ในเครือข่ายและเครื่องที่อยู่ภายนอกสามารถเชื่อมต่อได้

connection timeout (การเชื่อมต่อหมดเวลา)

โดยทั่วไปเป็นเพราะ:

  1. ไฟร์วอลล์ของเซิร์ฟเวอร์ไปยังการเชื่อมต่อ คุณสามารถลองปิดไฟร์วอลล์ชั่วคราว
  2. หากเป็นเซิร์ฟเวอร์คลาวด์ กลุ่มความปลอดภัยอาจจะขัดข้องในการสร้างการเชื่อมต่อ ควรเปิดพอร์ตที่เหมาะสมในหน้าจอดูแลระบบ
  3. หากใช้การควบคุมเชิงกระดอน เช่น Control Panel จะต้องเปิดพอร์ตที่เหมาะสมใน Control Panel
  4. เซิร์ฟเวอร์ไม่มีหรือไม่ได้เริ่มต้น
  5. หากผู้ใช้เชื่อมต่อโดยใช้ชื่อโดเมน อาจมีโดเมนชี้ไปที่ไอพีเซิร์ฟเวอร์ที่ผิด
  6. ไอพีที่เชื่อมต่อของลูกค้าเป็นไอพีภายในเซิร์ฟเวอร์และไคพีเซิร์ฟเวอร์และลูกค้าไม่ได้อยู่ในเครือข่ายเดียวกัน

ไม่สามารถกำหนดที่อยู่ที่ร้องขอได้ (Cannot assign requested address)

ในบทบาทของลูกค้า ทุกครั้งที่ที่เริ่มต้นการเชื่อมต่อ จะต้องใช้พอร์ตชั่วคราวของเครื่องที่ตั้งเริ่มต้น ซึ่งเซิร์ฟเวอร์หนึ่งเครื่องมีจำนวนพอร์ตชั่วคราวที่สามารถใช้ประมาณ 2-3 หมื่น หากมีการเชื่อมต่อที่เริ่มต้นกับเซิร์ฟเวอร์ที่ระบุพอร์ตเกินค่าที่กำหนดจะเกิดข้อผิดพลาดนี้ คุณสามารถเพิ่มจำนวนพอร์ตชั่วคราวที่กำหนดได้ในไฟล์ etc/sysctl.conf ในพารามิเตอร์ net.ipv4.ip_local_port_range เช่นการตั้งค่าเป็น 10000 65535 (กำหนดระยะช่วงของพอร์ตชั่วคราวเป็น 10000 ถึง 65535 ดังนั้นจำนวนพอร์ตชั่วคราวเพิ่มเป็น 55535 ช่วง) และทำการรัน sysctl -p เพื่อให้เกิดผล อย่างไรก็ตามหลังจากการเชื่อมต่อสิ้นสุดลง การเชื่อมต่อยังคงอยู่ในสถานะ TIME_WAIT ทำให้ยังคงใช้พอร์ตที่ร้องขอกับเครื่องที่ตั้งเป็นเวลา ดังนั้นการเชื่อมต่อที่มีจำนวนมากภายในเวลาสั้น (เกิน 2-3 หมื่น) ก็จะแสดงข้อผิดพลาด Cannot assign requested address หากเป็นกรณีนี้คุณสามารถแก้ไขปัญหาโดยการตั้งค่าการรับซ้ำของ TIME_WAIT โดยอ้างอิงการปรับแต่งการทำงานของคำสั่ง

ข้อควรระวัง
การจำกัดจำนวนของพอร์ตชั่วคราวเฉพาะต่อลูกค้าเท่านั้น ซึ่งเซิร์ฟเวอร์ไม่จำกัดจำนวนของพอร์ตชั่วคราว ถ้าทรัพยากรเพียงพอ เซิร์ฟเวอร์สามารถรักษาจำนวนการเชื่อมต่อได้มากที่แทบจะไม่จำกัดเลย

ข้อผิดพลาดอื่น ๆ

หากเกิดข้อผิดพลาดที่ไม่ใช่ connection refuse และ connection timeout โดยทั่วไปเป็นเพราะ:

1. การใช้โปรโตคอลการสื่อสารของลูกค้าและเซิร์ฟเวอร์ไม่ตรงกัน
เช่น เซิร์ฟเวอร์เป็นโปรโตคอลการสื่อสารhttp ลูกค้าใช้โปรโตคอลการสื่อสารเว็บซ็อกเก็ตไม่สามารถเชื่อมต่อ ถ้าลูกค้าใช้โปรโตคอลการสื่อสารเว็บซ็อกเก็ตที่เชื่อมต่อ จึงเซิร์ฟเวอร์จำเป็นจะต้องเป็นโปรโตคอลการสื่อสารเว็บซ็อกเก็ต ถ้าเซิร์ฟเวอร์เป็นโปรโตคอลการสื่อสารโปรโตคอลการสื่อสารhttp ลูกค้าจำเป็นจะต้องใช้โปรโตคอลการสื่อสารhttp

หลักการที่แน่นอนนี้คือ เมื่อคุณต้องการพูดคุยกับคนอังกฤษ คุณต้องใช้ภาษาอังกฤษ หากต้องการพูดคุยกับคนญี่ปุ่น คุณต้องใช้ภาษาญี่ปุ่น การใช้งานโปรโตคอลสื่อสารนี้มีความคล้ายคลึงกันภาษา เจ้าของอุปกรณ์และเซิร์ฟเวอร์ต้องใช้โปรโตคอลสื่อสารร่วมกันเพื่อพูดคุย ไม่เช่นนั้นก็ไม่สามารถสื่อสารได้

ข้อผิดพลาดที่เกิดขึ้นเนื่องจากโปรโตคอลการสื่อสารที่ไม่ตรงกันประกอบด้วย:

การเชื่อมต่อ WebSocket ไปยัง 'ws://xxx.com:xx/' ล้มเหลว: ข้อผิดพลาดในระหว่างการเฮ็นดชุกของ WebSocket: รหัสการตอบกลับที่ไม่ได้คาดการณ์: xxx

การเชื่อมต่อ WebSocket ไปยัง 'ws://xxx.com:xx/' ล้มเหลว: ข้อผิดพลาดในระหว่างการเฮ็นดชุกของ WebSocket: net::ERR_INVALID_HTTP_RESPONSE

วิธีการแก้ไข:
จากข้อผิดพลาดสองข้อด้านบน จะเห็นว่าลูกค้าใช้การเชื่อมต่อเวบซ็อกเก็ตคือโปรโตคอลการสื่อสารเว็บซ็อกเก็ต เซิร์ฟเวอร์จำเป็นต้องเป็นโปรโตคอลการสื่อสารเว็บซ็อกเก็ต ส่วนที่เป็นการเชื่อมต่อของเซิร์ฟเวอร์ต้องระบุโปรโตคอลการสื่อสารเว็บซ็อกเก็ตเท่านั้น เช่นที่แสดงในส่วนของการตรวจสอบเช่นนี้

หากเป็นการทำงานแบบเกตเวย์เวิร์กเกตเวิร์คเกตฟังขั้นตอนดังนี้

// โปรโตคอลการสื่อสารเว็บซ็อกเก็ต รหัสถือพอร์ตได้แก่ xxxx
$gateway = new Gateway('websocket://0.0.0.0:xxxx');

ถ้าเป็น Workerman คือ

// โปรโตคอลการสื่อสารเว็บซ็อกเก็ต รหัสถือพอร์ตได้แก่ xxxx
$worker = new Worker('websocket://0.0.0.0:xxxx');