Asynchronous Socket Client Buffer Size
Asked Answered
F

1

7

I have to connect a remote server with asynchronous socket connection and retrieve data. I can connect but there is a problem.

Packages are sending by pieces. I have two options; I can set a buffer and get whole package in one piece or combine pieces when all transfer done. I think first option (buffer thing) is the right way.

I'm defining a buffer size but it is not working in first part. In other parts, it works but with this method I can not get whole package in one piece because first part limited with 5,24 Kb.

You can find my code below:

$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();

I tried to define a buffer size under $stream->on('data', function ($data) { line but as you guess it failed. I don't know how to handle it right way.

Thanks in advance.

Furmenty answered 9/4, 2016 at 5:49 Comment(0)
S
4

"I can set a buffer and get whole package in one piece or combine pieces when all transfer done. I think first option (buffer thing) is the right way."

First option is not the right way simply because it's not the way socket communication works.

If you are receiving, for example, 5 kB of data and you set your buffer to be large enough, let's say 10 kB, you cannot expect that in one call to $stream->on('data', function ($data) { ... you will receive all 5 kB.

You must do three things:

  • You need to know the exact size of the data you are receiving in one message block. Either you know that the message will always have fixed and known size, or the data block has a header from which the length of the message can be read. In your case you are reading the message size from the first 4 bytes of the received data.
  • In loop you need to read the data chunks which come from the server and concatenate them until you have enough bytes to read the size of the whole message. In your case this is 4 bytes. However weird it sounds, there is a possibility that you receive 1 and then 3 bytes in two chunks, in two calls to $stream->on('data', function ($data) { .... When the size of concatenated data is >=4 then you read the size of the message.
  • In the same loop, you need to continue reading the data chunks which come from the socket and concatenate them until you receive all of the message bytes. Of course, this means that you need to have a variable defined outside of the loop in which you will store received data. After you received the whole message then you need to exit the loop.

Good idea is that you set a timer for loop so you can wait for the whole message to be received for a limited amount of time. It could happen that connection between client and server gets broken during transmission and if you do not have a timeout logic your loop will wait forever for the whole message to be received.

Stelmach answered 20/4, 2016 at 15:31 Comment(2)
Actually I did try a lot of things including your suggestions but the result is same.Furmenty
Hm, you have not stated what exact problem you have. Please post what you receive as a result and what is expected. If you are receiving more packages than one in one response, then you need to have additional logic. When all the data for one package has arrived usually you will get a part of the next package in the same response. This excess data you need to save and use in next iteration as starting data.Stelmach

© 2022 - 2024 — McMap. All rights reserved.