rybakit / msgpack.php

A pure PHP implementation of the MessagePack serialization format / msgpack.org[PHP]
MIT License
388 stars 18 forks source link

tryUnpack - how do you know when to return while streaming #19

Closed decebal closed 6 years ago

decebal commented 6 years ago

When reading from an open socket how do you know if you read all the bits and pieces of the packed message so that you should return the data. I am looking for a mechanism to replace streaming like this: msgpack-php extension

Here is what I tried, but it only ends in a loop that never returns, I need a stop, a way of knowing when the message is complete:

         stream_set_blocking($io, 0);
         $unpackedBlocks = null;
         $unpacker = new BufferUnpacker();

        while (!feof($io)) {
            $r = array($io);
            $n = null;
            stream_select($r, $n, $n, null);
            $read = fread($io, $size);
            if ($read === false) {
                throw new MessagePackRPCNetworkException(error_get_last());
            }
            $unpacker->append($read);
            $unpackedBlocks = $unpacker->tryUnpack();
        }

        return $unpackedBlocks;
rybakit commented 6 years ago

A non-empty result of the $unpacker->tryUnpack() call indicates that the entire msgpack message (or several) has been received and unpacked. If you expect only one message from a stream, you can just do:

if ($unpackedBlocks = $unpacker->tryUnpack()) {
    return $unpackedBlocks[0];
}

If you receive an unknown number of msgpack messages from the stream, then I guess feof() is the right way to break the loop.

decebal commented 6 years ago

that was so simple, I can't believe I didn't figure that out. I was trying to compare the lengths somehow.. Here's my snippet now:

         stream_set_blocking($io, 0);
         $unpackedBlocks = null;
         $unpacker = new BufferUnpacker();

        while (!feof($io)) {
            $r = array($io);
            $n = null;
            stream_select($r, $n, $n, null);
            $read = fread($io, $size);
            if ($read === false) {
                throw new MessagePackRPCNetworkException(error_get_last());
            }
            $unpacker->append($read);
            $unpackedBlocks = $unpacker->tryUnpack();
            if ($unpackedBlocks) {
                  return $unpackedBlocks;
            }
        }

        throw new RPCNetworkException("Could not read the server response!");

Also this allows me to process multiple messages at once!