PHPでネットワークソケットを操作する場合、エラー処理は常に頭痛の種です。 PHPは関数socket_clear_error()を提供しますが、公式ドキュメントでは、その使用シナリオを非常に簡単に説明しているため、多くの開発者がこの関数を使用する時期を不明確にします。
この記事では、実際のケースを組み合わせて、 socket_clear_error()の該当するシナリオを整理し、ソケットエラーをよりエレガントに処理する方法の例を示します。
socket_clear_error()は、現在のソケット接続エラーステータスをクリーンアップするために特別に使用されるPHPのソケット拡張機能の関数です。簡単に言えば、ソケット接続のエラーフラグを「リセット」できます。
公式ドキュメントでは、 socket_clear_error()は関数の署名と文の説明のみを書き込みます。
bool socket_clear_error ( resource $socket )
ソケットエラーステータスをクリアします。
しかし、それはいつ呼び出される必要があるか、またはそれがもたらす効果を指定しません。
ネットワーク伝送プロセス中、切断、データの送信の失敗、ネットワークの閉塞など、さまざまなエラーが発生する可能性があります。 PHPのソケット関数は通常、 falseを返し、エラーコードを設定します。 socket_last_error()を使用してエラーコードを取得し、 socket_strerror()を使用して読み取り可能な情報に変換します。
ただし、これらのエラーメッセージは手動でクリーンアップされるまで「継続」します。そうしないと、以前のソケット操作が以前のエラーの影響を受ける可能性があり、結果として誤判断します。
簡単な例を示すには:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'm66.net', 80);
socket_write($socket, "GET / HTTP/1.1\r\nHost: m66.net\r\n\r\n");
$errorCode = socket_last_error($socket);
if ($errorCode !== 0) {
echo "エラーが発生しました:" . socket_strerror($errorCode) . PHP_EOL;
socket_clear_error($socket); // エラーステータスをクリーンアップします,後続の操作に影響を及ぼさないでください
}
// 引き続き使用します $socket 何か他のことをしてください
socket_clear_error()が呼び出されない場合、 Socket_last_error()への後続の呼び出しも以前のエラーコードを返し、論理的判断の混乱を引き起こす場合があります。
非ブロッキングモードでは、ソケットの操作が完了を待つことはなく、エラーコードEagainまたはeWouldBlockが返されると、データが一時的に利用できないことを示す場合があります。このエラーは実際の障害ではありません。後で再試行するようにプログラムに指示するだけです。
エラー状態がクリーニングされていない場合、プログラムは接続に問題があると誤って考えるため、接続が事前に閉じられます。
socket_set_nonblock($socket);
while (true) {
$data = socket_read($socket, 2048);
if ($data === false) {
$err = socket_last_error($socket);
if ($err === SOCKET_EAGAIN || $err === SOCKET_EWOULDBLOCK) {
socket_clear_error($socket);
// 現時点ではデータはありません,後でもう一度やり直してください
usleep(100000);
continue;
} else {
// その他のエラー,処理または終了
break;
}
}
echo $data;
}
長時間保持されているソケット接続は、一時的なエラーに複数回遭遇する可能性があります。以前のエラーステータスのために後続の操作が失敗しないようにするために、操作が完了した後にsocket_clear_error()を呼び出すことは良い習慣です。
socket_clear_error()は、ソケットの現在のエラー状態をクリーンアップする機能です。
一時的に利用できないことによって引き起こされる誤判断を避けるために、非ブロッキングソケットプログラミングでよく使用されます(eagain/ewouldblock)。
マルチプレックスまたは長い接続シナリオでは、エラーステータスがリセットされ、その後の操作が正常であることを確認するためにも使用できます。
呼び出されない場合、エラーステータスが保持され、 socket_last_error()が期限切れのエラーコードを返し、ビジネスロジックに影響します。
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$socket) {
die("作成できません socket: " . socket_strerror(socket_last_error()) . PHP_EOL);
}
if (!socket_connect($socket, 'm66.net', 80)) {
die("接続に失敗しました: " . socket_strerror(socket_last_error($socket)) . PHP_EOL);
}
socket_set_nonblock($socket);
$request = "GET / HTTP/1.1\r\nHost: m66.net\r\nConnection: close\r\n\r\n";
socket_write($socket, $request);
while (true) {
$data = socket_read($socket, 2048);
if ($data === false) {
$err = socket_last_error($socket);
if ($err === SOCKET_EAGAIN || $err === SOCKET_EWOULDBLOCK) {
socket_clear_error($socket);
usleep(100000); // 待って 0.1 数秒でもう一度読んでください
continue;
} else {
echo "エラーを読み取ります:" . socket_strerror($err) . PHP_EOL;
break;
}
} elseif ($data === '') {
// 接続が閉じます
break;
}
echo $data;
}
socket_close($socket);
このコードは、socket_clear_error()を使用して、非ブロッキングモードで一時的なデータフリーエラーを無視し、HTTP応答を正常に読み取る方法を示しています。
このようにして、 socket_clear_error()の役割と使用法が明確になります。ノンブロッキング、長い接続、その他のシナリオでタイムリーにエラーステータスをクリーンアップすることを忘れないでください。これにより、ソケットプログラムをより堅牢にすることができます。