PHPを使用してソケットベースのサーバーまたはクライアントプログラムを構築する場合、永続的な接続は非常に一般的な要件です。特に、インスタントメッセージング、オンラインゲームサーバー、データプッシュなどのシナリオでは、ソケットを長時間接続し、常に並べることは、パフォーマンスとユーザーエクスペリエンスに大きな影響を与えます。
このシナリオでは、 socket_clear_error()の合理的な使用は、接続を安定させるための重要な手段です。この記事では、それがどのように使用されるかを詳細に調べ、いくつかの実用的な例を組み合わせて、不明確なエラーによる接続の中断を避ける方法を説明します。
socket_clear_error()は、指定されたソケットに関連付けられたエラー情報をクリアするためにPHPによって提供されるソケット操作機能です。関数の署名は次のとおりです。
void socket_clear_error ([ resource $socket ] )
特定のソケットまたはグローバルで使用できます。ソケット操作でエラーが発生すると、エラーメッセージが保存されます。これらのエラーが時間内にクリアされていない場合、次にソケット機能が呼び出されたときに動作に影響し、接続が切断される可能性があります。
次のような長い接続を使用する場合、切断には多くの理由があります。
ネットワークジッター;
クライアントは接続を閉じます。
サーバー内部処理エラーはキャッチされていません。
エラースタッキングはクリアされていません。
最後のものは、私たちの記事の焦点です。わずかな非脂肪エラーであっても、 socket_clear_error()を介してクリアされていない場合、 socket_write()やsocket_read()などの次回は異常に戻るか、「エラー状態」が検出されたために割り込みをトリガーする場合があります。
以下は、クライアントのリクエストを処理し、長い接続を維持する典型的なPHPソケットサーバー側のコードスニペットです。
$host = '0.0.0.0';
$port = 9000;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, $host, $port);
socket_listen($socket);
$clients = [];
while (true) {
$read = $clients;
$read[] = $socket;
$write = $except = null;
socket_select($read, $write, $except, 0, 200000); // ノンブロッキング
if (in_array($socket, $read)) {
$client = socket_accept($socket);
$clients[] = $client;
socket_clear_error($client); // 新しい接続のエラーステータスをクリアします
}
foreach ($clients as $key => $client) {
$data = @socket_read($client, 1024, PHP_NORMAL_READ);
if ($data === false) {
$error = socket_last_error($client);
if ($error !== 0) {
echo "Socket error: " . socket_strerror($error) . "\n";
socket_clear_error($client);
}
continue;
}
$data = trim($data);
if ($data == 'quit') {
socket_close($client);
unset($clients[$key]);
continue;
}
$response = "Server received: $data\n";
@socket_write($client, $response, strlen($response));
socket_clear_error($client); // 各通信後のクリアエラー
}
}
このコードは、いくつかの重要な戦略を示しています。
クライアント接続を受信するたびに、 socket_clear_error()を使用してステータスをすぐにクリアします。
読み取りまたは書き込み操作のたびに可能なエラーをクリアします。
非脂肪のエラー(一時的なネットワークの停止など)の場合、すぐに切断するのではなく、処理をクリアして継続してみてください。
クリアのエラーに加えて、「ハートビートパッケージ」を合理的に設計することも、接続を常に維持するための鍵です。ハートビートメカニズムにより、クライアントは固定時間に軽量データパケットをサーバーに送信できます。一定期間後にハートビートが受信されない場合、接続を自動的に閉じることができます。
// ハートビート応答の例の簡素化されたバージョン
if ($data == 'ping') {
@socket_write($client, "pong\n");
socket_clear_error($client);
}
これにより、socket_clear_error()を使用した「実際の壊れた線」と「誤差線」の違いをよりよく検出できます。
エラーを長時間クリアしないと、いわゆる「ゾンビ接続」が発生します。つまり、ソケットオブジェクトはまだ存在しますが、すでに無効な状態です。すべてのクライアントのステータスを定期的に確認する方法は次のとおりです。