PHPでネットワークプログラミングにソケットを使用する場合、非ブロッキングモードは同時処理機能を改善し、イベント駆動型または多重化サーバーを実装する鍵です。ただし、大規模なデータパケットを完全に読み取るか、クライアントが完全なハンドシェークデータを送信するのを待つなど、特定の「待機」操作を完了するために、ソケットを一時的にブロック状態に設定する必要がある場合があります。
幸いなことに、PHPは2つの機能を提供します: socket_set_block()とsocket_set_nonblock() 。ブロッキングモードと非ブロッキングモードを簡単に切り替えることができます。
この記事では、特定のTCPサーバーの例を組み合わせて、ノンブロッキングリスニングでソケットをブロッキング状態に一時的に切り替え、操作を完了した後に非ブロッキング状態を復元する方法を示します。
非ブロッキングTCPサーバーを構築し、クライアント接続を聴き、クライアント接続を受信した後、接続を一時的にブロッキングモードに切り替え、クライアントからのデータを読み取り、完了後に非ブロッキングモードに切り替えます。
これが完全なコードです:
<code> <?php $ host = '0.0.0.0';
$ port = 12345;
//ソケットを作成します
$ server = socket_create(af_inet、sock_stream、sol_tcp);
socket_set_option($ server、sol_socket、so_reuseaddr、1);
//バインディングとリスニング
socket_bind($ server、$ host、$ port);
socket_listen($ server);
//非ブロッキングに設定します
socket_set_nonblock($ server);
echo "{$ host}で聞くサーバー}:{$ port} ... \ n";
$ clients = [];
while(true){
//接続を受け入れる(非ブロッキング)
$ client = @socket_accept($ server);
if($ client!== false){
echo "新しいクライアントConnected。\ n";
//クライアントリストに追加します
$ clients [] = $ client;
// クライアントを非ブロッキングに設定します
socket_set_nonblock($client);
}
foreach ($clients as $index => $sock) {
$buffer = '';
// 一時的にブロックするように設定して、完全な読み取りを確認します(たとえば、固定長または旗まで読む)
socket_set_block($sock);
$bytes = @socket_recv($sock, $buffer, 1024, MSG_DONTWAIT);
// 非ブロッキングに戻ります
socket_set_nonblock($sock);
if ($bytes === false || $bytes === 0) {
// クライアントが切断されました
echo "Client disconnected.\n";
socket_close($sock);
unset($clients[$index]);
continue;
}
// 出力読み取りデータ
echo "Received: " . trim($buffer) . "\n";
// サンプル応答
$response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello from server!\n";
socket_write($sock, $response);
}
// わずかな遅延回避 CPU 満杯
usleep(100000);
}
socket_close($ server);
?>
</code>
上記のコードでは、リスニングソケット($サーバー)は非ブロッキングであるため、 socket_accept()でブロックしません。新しい接続が受け入れられるたびに、新しいクライアントを非ブロッキングに設定します。ただし、受信データを処理する部品では、 socket_recv()が予想されるデータを完全に受信し、データの不完全性を回避できるようにするため、クライアントソケットを積極的にブロッキングモードに切り替えます。
これは非常に一般的な混合使用方法であり、多くのシナリオ(プロトコルハンドシェイクフェーズなど)で特に重要です。たとえば、クライアントが固定ヘッダー情報を初めて含める必要があり、サーバーが処理を継続する前に完全に受信する必要があることを規定する簡単なプロトコルを設計しました。この時点で、ブロッキングの読み取り値を使用することは非常に意味があります。
スイッチングモードの場合は注意してください:非ブロッキングプロセスで一時的にブロック読み取り値を使用することは、「強制待機」方法です。便利ですが、クライアントがデータを送信しない場合、サーバーは立ち往生します。タイムアウトメカニズムまたはプリセットデータの長さに一致することをお勧めします。
短期ブロッキングに適しています:このタイプのモードスイッチングは、特定の操作をブロックする必要があり、通信プロセス全体でブロッキングを使用することをお勧めしない状況に適しています。
socket_set_block()とsocket_set_nonblock()を使用して、PHPソケットプログラミングをより柔軟にします。処理ロジックに従って適切なブロッキングモードを柔軟に選択でき、効率と完全性を考慮して説明できます。
ソケットプログラミングの練習と例については、ドキュメントを参照するか、リソースプラットフォームにアクセスしてください。