2

非ブロッキング方式で大量のデータ (~250K) をストリームに書き込もうとしています。

複雑さとオブジェクト構造を抽象化して、これが私が実行しているものです。

$fp = fsockopen('host', 80);
socket_set_blocking( $fp, false );
fwrite( $fp, $string, $length ); // Where $string is a 250K string

ただし、データがすべて書き込まれるわけではありません。これは PHP の書き込みバッファが機能していると仮定して、設定stream_set_write_buffer( $fp, 0 )しましたが、それでも問題は解決しませんでした。

fwrite を 4096B のチャンクに分割しました。クライアントが 3 つの完全なバッチ (4096 バイト) と 4 つ目のバッチの ~1500B を送信したようです。fwrite を連続して呼び出すと、書き込まれた 0 バイトが返されます。

このデータをすべて非ブロッキング方式で送信するためにキューに入れる方法を知っている人はいますか? 削除するsocket_set_blocking( $fp, false );と、すべて正常に動作します。明らかに、非同期で実行する際の問題です。

あなたの考えは何ですか?ソケット拡張機能はここでまったく役に立ちますか? バッファの扱いは異なりますか?

注: さまざまな理由で curl を使用しないように、意図的にこのソケット トランスポート レイヤーを作成しています。使用curl_multi()はオプションではありません。

4

2 に答える 2

5

あなたの問題は、ほぼ確実に、fwrite非ブロッキング ソケット ストリームでの操作が新しいパケットの到着によって中断される可能性があるという事実によるものです。fwriteその結果、がアトミックであるとは期待できません。そのような場合、呼び出しの戻り値に依存して、そのパスでストリームに書き込まれたバイト数を正確に伝え、すべてのデータが送信されるまで書き込みを続ける必要がありますfwrite

例えば ​​...

$dataToWrite = 'my data';
$bytesToWrite = strlen($dataToWrite);
$totalBytesWritten = 0;

while ($totalBytesWritten < $bytesToWrite) {
    $bytes = fwrite($mySock, substr($dataToWrite, $totalBytesWritten));
    $totalBytesWritten += $bytes;
}

明らかに、この問題を確実に処理するには、ソケット接続が失われた場合などの状況も考慮する必要があります。

于 2012-11-15T03:12:50.053 に答える
0

ブロックと再試行を考慮していますか? EAGAIN/EWOULDBLOCK/EINTR 状態を説明する必要があると思います。そうしないと、自分自身をブロックすることになります。

于 2012-11-15T03:12:41.777 に答える