7

非同期ソケット接続でリモート サーバーに接続し、データを取得する必要があります。接続できますが、問題があります。

パッケージは分割して送信されます。2 つのオプションがあります。バッファーを設定して、すべての転送が完了したら、パッケージ全体を 1 つにまとめたり、断片を結合したりできます。最初のオプション(バッファのこと)が正しい方法だと思います。

バッファ サイズを定義していますが、最初の部分では機能しません。他の部分では機能しますが、この方法では、最初の部分が 5,24 KB に制限されているため、パッケージ全体を 1 つにまとめることはできません。

以下の私のコードを見つけることができます:

$loop = React\EventLoop\Factory::create();

        $dnsResolverFactory = new React\Dns\Resolver\Factory();
        $dns = $dnsResolverFactory->createCached('8.8.8.8', $loop);
        $connector = new React\SocketClient\Connector($loop, $dns);
        $connector->create( ENDPOINT_IP , ENDPOINT_PORT )->then(function (React\Stream\Stream $stream) use ($loop) {

            $command = '{C:"EL",bmId:43,inst:"my_instance",tok:"my_token"}';

            $command_length = strlen($command);
            $command_length = pack("N", $command_length);

            $stream->write($command_length);
            $stream->write($command);

            $stream->bufferSize = 999999;
            $stream->on('data', function ($data) {

            $package    =   substr($data, 0, 4);
            $unpack     =   unpack('N', $package); // I'm getting whole package size

            echo $data;



            });


        });

        $loop->run();

行の下にバッファサイズを定義しようとしました$stream->on('data', function ($data) {が、ご想像のとおり失敗しました。正しい方法で処理する方法がわかりません。

前もって感謝します。

4

1 に答える 1

4

「バッファを設定してパッケージ全体を 1 つにまとめるか、すべての転送が完了したら複数のパーツを組み合わせることができます。最初のオプション (バッファ処理) が正しい方法だと思います。」

最初のオプションは、ソケット通信が機能する方法ではないため、正しい方法ではありません。

たとえば、5 kB のデータを受信して​​いて、10 kB などの十分な大きさのバッファを設定した場合、1 回の呼び出しで$stream->on('data', function ($data) { ...5 kB すべてを受信できるとは期待できません。

次の 3 つのことを行う必要があります。

  • 1 つのメッセージ ブロックで受信するデータの正確なサイズを知る必要があります。メッセージが常に固定された既知のサイズであることがわかっているか、データ ブロックにメッセージの長さを読み取ることができるヘッダーがあります。あなたの場合、受信したデータの最初の 4 バイトからメッセージ サイズを読み取っています。
  • ループでは、サーバーからのデータチャンクを読み取り、メッセージ全体のサイズを読み取るのに十分なバイト数になるまでそれらを連結する必要があります。あなたの場合、これは4バイトです。奇妙に聞こえるかもしれませんが、 を 2 回呼び出して、1 バイトと 3 バイトを 2 つのチャンクで受け取る可能性があります$stream->on('data', function ($data) { ...。連結データのサイズが の場合>=4、メッセージのサイズを読み取ります。
  • 同じループ内で、ソケットからのデータ チャンクの読み取りを続行し、すべてのメッセージ バイトを受信するまでそれらを連結する必要があります。もちろん、これは、受信したデータを格納するループの外で変数を定義する必要があることを意味します。メッセージ全体を受信したら、ループを終了する必要があります。

ループのタイマーを設定して、限られた時間だけメッセージ全体が受信されるのを待つことをお勧めします。送信中にクライアントとサーバー間の接続が切断される可能性があり、タイムアウト ロジックがない場合、ループはメッセージ全体が受信されるまで永遠に待機します。

于 2016-04-20T15:31:49.743 に答える