PHPネットワークプログラミングでは、 Stream_Socket_Shutdown関数を使用して、ソケット接続の特定の方向(読み取り、書き込み、またはその両方)を閉じます。ただし、実際に使用すると、多くの開発者は、 stream_socket_shutdownを呼び出した後の異常な接続の中断、クライアントエラー、さらにはデータ損失などの問題に遭遇します。この記事では、 stream_socket_shutdownの作業メカニズムを詳細に分析し、接続の例外の原因を調査し、回避して修復する方法を提供します。
stream_socket_shutdownの関数定義は次のとおりです。
bool stream_socket_shutdown(resource $stream, int $how)
$ストリーム:オープンソケットストリームリソース。
$ how :方向を閉じて、値を取ります:
stream_shut_rd (0)読み取り方向を閉じます
stream_shut_wr (1)書き込み方向を閉じます
stream_shut_rdwr (2)読み取りと書き込みの指示をオフにします
例えば:
$socket = stream_socket_client("tcp://m66.net:8080", $errno, $errstr, 30);
if (!$socket) {
die("接続に失敗しました: $errstr ($errno)");
}
// ライティングの方向を閉じます,データが送信されなくなったことを示します
stream_socket_shutdown($socket, STREAM_SHUT_WR);
Stream_socket_shutdownを呼び出した後、ソケットの特定の方向が閉じられ、カーネルはフィンパケットをピアに送信し、接続が閉じていることを示します。
例外の根本的な原因は、 Stream_Socket_Shutdownを使用する場合、クライアントまたはサーバーが接続のシャットダウン信号を適切に処理しないか、クロージング順序が不適切であることです。具体的には次のように現れます。
事前に書き込み方向を閉じて、ピアがデータの読み取りが終了しないときに接続が切断されます。
同時に、読み取りと書き込みの方向はオフになりますが、データは読み取られておらず、データの損失になります。
書き込み方向を閉じた後、残りのデータは時間内に読み取られず、異常な接続が生じます。
FINパケットはピアによって処理されず、タイムアウトと切断への接続が発生します。
これらの問題は、TCP Long ConnectionまたはHalf-Duplex通信シナリオで特に発生する傾向があります。
データを送信するだけで、もう一度書くことを計画していない場合は、次のように電話してください。
stream_socket_shutdown($socket, STREAM_SHUT_WR);
つまり、書き込み方向が閉じられていることを意味しますが、読み取り方向はまだ保持されており、ピアから送信されたデータを待っています。
サーバーとクライアントの両方が最初に書き込み方向をオフにする必要がある場合は、ピアが残りのデータを読み取るのに十分な時間があることを確認してください。
書き込み方向を閉じた後、接続はまだデータを読み取ることができます。一般的なアプローチは次のとおりです。
// ライティングの方向を閉じます
stream_socket_shutdown($socket, STREAM_SHUT_WR);
// までピアデータを読み続けますEOF
while (!feof($socket)) {
$data = fread($socket, 8192);
if ($data === false) {
break;
}
// データの処理
}
レガシーデータが読まれないことを確認してください。
まず、書き込み方向を閉じて、ピアデータに送信されるように通知します。
ピアが返す可能性のあるデータを読んでください。
読み取り後、読み取り方向を閉じるか、接続全体を閉じます。
Stream_set_timeoutを使用して、読み取りと書き込みのタイムアウトを設定して、接続のハングをブロックしないようにします。
次の例は、サーバーに安全な接続を書き込む正しい方法を示しています。
$server = stream_socket_server("tcp://0.0.0.0:12345", $errno, $errstr);
if (!$server) {
die("サーバーを起動できません: $errstr ($errno)");
}
$client = stream_socket_accept($server);
if ($client) {
// 応答データを送信します
fwrite($client, "Hello from server\n");
// ライティングの方向を閉じます,これ以上のデータがないことをクライアントに通知します
stream_socket_shutdown($client, STREAM_SHUT_WR);
// クライアントが送信したデータを引き続き読み取ります
while (!feof($client)) {
$data = fread($client, 8192);
if ($data === false || $data === "") {
break;
}
echo "クライアントデータを受信しました: $data\n";
}
// 接続を閉じます
fclose($client);
}
fclose($server);
通信が行われなくなったと確信していない限り、読み取りと書き込みの指示を同時に避けないでください。
長い接続については、 Stream_Socket_Shutdownへの頻繁な呼び出しを避け、ハートビートパッケージとタイムアウト検出を合理的に使用します。
クライアントとサーバーのプロトコル設計が、接続の閉鎖のタイミングと順序について明確であることを確認してください。
stream_set_blockingとstream_set_timeoutを使用して、ブロッキングを防ぎます。
Stream_Socket_Shutdownはソケット接続を閉じるための重要なツールですが、不適切な使用は簡単に異常な接続中断につながる可能性があります。閉鎖のセマンティクスを理解し、閉鎖方向を合理的に選択し、閉鎖後にデータの読み取りと書き込みの順序を確保することは、問題を回避して修正するための鍵です。正しいタイムアウト設定と例外処理を組み合わせることで、PHPネットワークプログラムがより安定して信頼性を高めることができます。