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

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

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

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

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

7

Решение

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

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

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

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

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

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

4

Другие решения

Других решений пока нет …