クライアント接続失敗の原因

接続に失敗したクライアントは一般的に以下の2つのエラーメッセージを表示します:connection refusedconnection timeout

connection refused(接続拒否)

一般的な原因は以下の通りです:

  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(リクエストされたアドレスを割り当てられません)

クライアントとして、接続を開始するたびにローカルの一時ポートを占有する必要があります。一台のサーバーはデフォルトで約2-3万の一時ポートを利用可能です。この値を超えて特定のサーバーに対する接続が発生すると、利用可能なポートを割り当てることができず、このエラーが発生します。
/etc/sysctl.confnet.ipv4.ip_local_port_rangeを変更することで、ローカルの一時ポートの数を増やすことができます。例えば、10000 65535に設定すると(ローカルポート範囲が10000-65535になり、ローカルポート数が55535に増加します)、sysctl -pを実行することで変更が有効になります。
接続が切断された後、接続はTIME_WAIT状態になり、対応するローカルポートをしばらくの間使用し続けます。つまり、短期間に大量(2-3万を超える)の短い接続を開始すると、Cannot assign requested addressも発生します。この場合、カーネルにTIME_WAITを迅速に回収するよう設定することで解決できます。参考にしてくださいカーネル最適化

注意
ローカルポート数の制限はクライアントにのみ適用され、サーバーにはローカルポートの制限がありません。リソースが十分であれば、サーバーは接続数を無限に維持できます。

その他のエラー

connection refusedconnection 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

解決方法:
上記の2つのエラーメッセージから、クライアントが使用しているのは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');