PHPでは、 socket_export_stream()は非常に実用的な機能であり、低レベルのソケットリソースをより高度なストリームベースのストリームリソースにエクスポートできるため、ファイルや標準入力と出力などのソケットを処理できます。これにより、特にStream_Select() 、 Fread() 、 fwrite()などの既存のストリーミングAPIとコラボレーションする場合、開発プロセスが大幅に簡素化されます。
ただし、ソケットをストリームに変換した後、多くの開発者は一般的な問題に遭遇します。同じストリームでインターリーブされている読み取り操作を実行するときに競合が発生しやすく、データの例外、閉塞、または損失をもたらします。このタイプの問題の中核は、データフローの安定性と一貫性を確保するために、読み取りおよび書き込みプロセスを合理的に配置する方法にあります。
socket_export_stream()を呼び出してソケットをストリームに変換すると、PHPはストリームを読みやすく書き込み可能な機能を与えます。理論的には、 fread()とfwrite()で直接操作できます。ただし、読み取り操作がスケジュールされていない場合、次の問題が発生する可能性があります。
操作ブロッキングの書き込み:相手がデータを読み取らない場合、バッファがいっぱいのときにfwrite()を呼び出します。
読み取り操作ブロッキング: fread()を呼び出してくださいデータがない場合はブロックされます。
データの混乱:同時の読み取りと書き込みの同期は行われず、一貫性のないプロトコルと解析の障害をもたらします。
上記の問題を回避するために、使用中の安全で効率的なフローを確保するために、次の側面から始めてください。
ストリームを非ブロッキングモードに設定し、 Stream_Select()を使用して、ブロッキングを避けるためにいつ読み書きするかを決定します。
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'm66.net', 80);
$stream = socket_export_stream($socket);
stream_set_blocking($stream, false); // 非ブロッキングモードを設定します
$read = [$stream];
$write = [$stream];
$except = null;
if (stream_select($read, $write, $except, 5)) {
if (!empty($write)) {
fwrite($stream, "GET / HTTP/1.1\r\nHost: m66.net\r\n\r\n");
}
if (!empty($read)) {
$response = fread($stream, 8192);
echo $response;
}
}
このようにして、ストリームが書き込み可能である場合にのみ書き込みを制御でき、読みやすく、ブロッキングやリソースの無駄を避けている場合にのみ制御できます。
socket_export_stream()は双方向のストリームを返しますが、一部のプロトコルまたはアプリケーションでは、読み取りと書き込みロジックを分離すると競合を減らすことができます。レイヤープロトコル制御を適用するか、コルーチン/マルチプロセス/スレッドを導入することにより、読み取り操作を分離できます。
たとえば、 Stream_Socket_Pair()を使用して2つのローカルソケットストリームを作成します。1つは読み取りを担当し、もう1つは書き込みを担当し、データトランジットチャネルを構築します。
Stream_Select()が使用されないシナリオでは、プログラムにロックを明示的に追加したり、非同期フレームワーク(Swoole、ReactPhpなど)を使用して読み取り順序を制御することもできます。
$lock = fopen(__FILE__, 'r');
flock($lock, LOCK_EX);
// データを書き込みます
fwrite($stream, $data);
// ロック解除後にデータを読み取ります
flock($lock, LOCK_UN);
$response = fread($stream, 8192);
この方法は比較的原始的ですが、スクリプト化されたアプリケーションでの同時リソースの競合を効果的に回避できます。
ストリームを使用して書き込み操作を完了する場合、相手がすぐに読み取ることを期待する場合は、 fflush()に電話してバッファを更新してください。接続を閉じる前に、最初に書き込みの終わりを閉じることに注意し、読み取りの終わりを待って完全な読み取りを待ってから切断する必要があります。
fwrite($stream, $data);
fflush($stream);
fclose($stream);
socket_export_stream()を使用すると、ストリームの動作性が強化されますが、同期制御の課題も導入されます。読み取りと書き込みの競合を避けるために、次のことができます。
Stream_Select()を使用して正確にスケジュールします。
非ブロッキングモードと組み合わせて使用。
ロック、コルーチン、または非同期処理メカニズムを導入します。
バッファリフレッシュとクロージングタイミングを管理します。
これらの方法により、PHPネットワークプログラミングにおけるソケット変換ストリームの信頼性と保守性を効果的に改善できます。