Размер буфера клиента асинхронного сокета

Мне нужно подключить удаленный сервер с асинхронным подключением к сокету и получить данные. Я могу подключиться, но есть проблема.

Посылки отправляются поштучно. У меня есть два варианта; Я могу установить буфер и получить весь пакет одним куском или объединить части, когда все пересылки будут завершены. Я думаю, что первый вариант (буфер) - правильный путь.

Я определяю размер буфера, но он не работает в первой части. В других частях это работает, но с помощью этого метода я не могу получить весь пакет одним куском, потому что первая часть ограничена 5,24 Кб.

Вы можете найти мой код ниже:

$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) {, но, как вы догадываетесь, это не удалось. Я не знаю, как справиться с этим правильно.

Заранее спасибо.


person Deniz B.    schedule 09.04.2016    source источник


Ответы (1)


"Я могу установить буфер и получить весь пакет одним куском или объединить части, когда все пересылки будут завершены. Я думаю, что первый вариант (буфер) является правильным путем."

Первый вариант неправильный просто потому, что это не тот способ, которым работает связь через сокеты.

Если вы получаете, например, 5 КБ данных и устанавливаете достаточно большой буфер, скажем, 10 КБ, вы не можете ожидать, что за один вызов $stream->on('data', function ($data) { ... вы получите все 5 КБ.

Вы должны сделать три вещи:

  • Вам нужно знать точный размер данных, которые вы получаете в одном блоке сообщений. Либо вы знаете, что сообщение всегда будет иметь фиксированный и известный размер, либо блок данных имеет заголовок, из которого можно прочитать длину сообщения. В вашем случае вы читаете размер сообщения из первых 4 байтов полученных данных.
  • В цикле вам нужно прочитать фрагменты данных, поступающие с сервера, и сцепить их, пока у вас не будет достаточно байтов, чтобы прочитать размер всего сообщения. В вашем случае это 4 байта. Как бы странно это ни звучало, есть вероятность, что вы получите 1, а затем 3 байта двумя кусками, за два обращения к $stream->on('data', function ($data) { .... Когда размер объединенных данных равен >=4, вы читаете размер сообщения.
  • В том же цикле вам нужно продолжать читать фрагменты данных, которые поступают из сокета, и объединять их, пока вы не получите все байты сообщения. Конечно, это означает, что вам нужно иметь переменную, определенную вне цикла, в котором вы будете хранить полученные данные. После того, как вы получили все сообщение, вам нужно выйти из цикла.

Хорошая идея заключается в том, что вы устанавливаете таймер для цикла, чтобы вы могли ждать получения всего сообщения в течение ограниченного периода времени. Может случиться так, что соединение между клиентом и сервером будет разорвано во время передачи, и если у вас нет логики тайм-аута, ваш цикл будет вечно ждать получения всего сообщения.

person BJovke    schedule 20.04.2016
comment
На самом деле я пробовал много вещей, включая ваши предложения, но результат тот же. - person Deniz B.; 22.04.2016
comment
Хм, вы не указали, какая именно у вас проблема. Пожалуйста, напишите, что вы получили в результате и что ожидается. Если вы получаете больше пакетов, чем один в одном ответе, вам нужна дополнительная логика. Когда все данные для одного пакета получены, обычно вы получаете часть следующего пакета в том же ответе. Эти лишние данные вам нужно сохранить и использовать в следующей итерации в качестве исходных данных. - person BJovke; 22.04.2016