Причины неудачного подключения клиента

При неудачном подключении клиента могут возникнуть две основные ошибки: connection refuse и connection timeout.

connection refuse (подключение отклонено)

Это обычно происходит по следующим причинам:

  1. Неправильный порт, используемый клиентом для подключения.
  2. Неправильный домен или IP-адрес, к которому обращается клиент.
  3. Если клиент использует домен для подключения, возможно, он указывает на неправильный IP-адрес сервера.
  4. Сервер использует CDN или другие прокси-сервисы, что приводит к несоответствию фактического IP-адреса с ожидаемым.
  5. Сервер не запущен или на порту нет прослушивания.
  6. Используется сетевое программное обеспечение для прокси.
  7. IP-адрес, на котором сервер слушает, и адрес, по которому происходит доступ, не находятся в одной подсети. Например, если сервер слушает на 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 (невозможно назначить запрашиваемый адрес)

В качестве клиента каждое инициированное соединение требует использования временного локального порта. На одном сервере по умолчанию доступно примерно 20-30 тысяч временных портов. Если количество соединений, инициированных к определенному серверу, превышает это значение, то не удается выделить доступный порт, что приводит к этой ошибке.
Можно увеличить количество локальных временных портов, изменив параметр ядра в файле /etc/sysctl.conf в строке net.ipv4.ip_local_port_range, например, установив на 10000 65535 (это увеличит количество локальных портов до 55535), затем выполните sysctl -p для применения изменений.
Кроме того, после разрыва соединения порты переходят в состояние TIME_WAIT и всё еще будут занимать соответствующий локальный порт в течение некоторого времени. Таким образом, при быстром инициировании большого количества (более 20-30 тысяч) коротких соединений также может возникнуть ошибка Cannot assign requested address. В этом случае можно решить проблему, настроив ядро для быстрого освобождения TIME_WAIT, см. оптимизация ядра.

Внимание
Ограничение количества локальных портов относится только к клиенту; у сервера нет такого ограничения, и с достаточными ресурсами сервер может поддерживать количество соединений как бесконечное.

Другие ошибки

Если возникает ошибка, отличная от connection refuse и connection timeout, это обычно вызвано следующими причинами:

1. Протокол связи, используемый клиентом, не соответствует протоколу сервера.
Например, если сервер использует HTTP-протокол, клиент, использующий WebSocket-протокол, не сможет подключиться. Если клиент подключается с помощью WebSocket-протокола, сервер также должен использовать WebSocket-протокол. Если сервер является HTTP-сервисом, клиент должен обращаться по HTTP-протоколу.

Принцип здесь похож на то, что если вы хотите общаться с англичанином, вам нужно использовать английский язык. Если вы хотите общаться с японцем, вам нужно использовать японский. Здесь язык соответствует протоколу связи, оба участника (клиент и сервер) должны использовать один и тот же язык для общения, в противном случае связь невозможна.

Общие ошибки, возникающие из-за несоответствия протоколов связи:

WebSocket connection to 'ws://xxx.com:xx/' failed: Error during WebSocket handshake: Unexpected response code: xxx

WebSocket connection to 'ws://xxx.com:xx/' failed: Error during WebSocket handshake: 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');