Размер асинхронного клиентского буфера
Я должен подключить удаленный сервер с асинхронным сокетом и получить данные. Я могу подключиться, но есть проблема.
Посылки отправляются поштучно. У меня есть два варианта; Я могу установить буфер и получить весь пакет в один кусок или объединить части, когда все передачи сделаны. Я думаю, что первый вариант (буферная вещь) - правильный путь.
Я определяю размер буфера, но он не работает в первой части. В других частях это работает, но с помощью этого метода я не могу получить весь пакет одним куском, потому что первая часть ограничена 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) {
линия, но, как вы думаете, это не удалось. Я не знаю, как справиться с этим правильно.
Заранее спасибо.
1 ответ
"Я могу установить буфер и получить весь пакет в виде одного куска или объединить его, когда все будет выполнено. Я думаю, что первый вариант (буферная вещь) - правильный путь".
Первый вариант - неправильный способ просто потому, что он не работает как сокетная связь.
Если вы получаете, например, 5 КБ данных и устанавливаете достаточно большой буфер, скажем, 10 КБ, вы не можете ожидать, что за один вызов $stream->on('data', function ($data) { ...
вы получите все 5 кБ.
Вы должны сделать три вещи:
- Вам нужно знать точный размер данных, которые вы получаете в одном блоке сообщений. Либо вы знаете, что сообщение всегда будет иметь фиксированный и известный размер, либо у блока данных есть заголовок, из которого можно прочитать длину сообщения. В вашем случае вы читаете размер сообщения из первых 4 байтов полученных данных.
- В цикле вам нужно прочитать порции данных, которые поступают с сервера, и объединить их, пока у вас не будет достаточно байтов для считывания размера всего сообщения. В вашем случае это 4 байта. Как бы странно это ни звучало, есть вероятность, что вы получите 1, а затем 3 байта в двух блоках, в двух вызовах
$stream->on('data', function ($data) { ...
, Когда размер объединенных данных>=4
Затем вы читаете размер сообщения. - В том же цикле вам необходимо продолжить чтение блоков данных, которые поступают из сокета, и объединять их до тех пор, пока вы не получите все байты сообщения. Конечно, это означает, что вам нужно иметь переменную, определенную вне цикла, в которой вы будете хранить полученные данные. После того, как вы получили все сообщение, вам нужно выйти из цикла.
Хорошая идея заключается в том, что вы устанавливаете таймер для цикла, чтобы вы могли ждать получения всего сообщения в течение ограниченного периода времени. Может случиться так, что соединение между клиентом и сервером будет разорвано во время передачи, и если у вас нет логики тайм-аута, ваш цикл будет ждать целое сообщение вечно.