GithubHelp home page GithubHelp logo

Comments (6)

clue avatar clue commented on June 13, 2024

@Tick007 Welcome to @reactphp! 👋

I agree ReactPHP can be confusing when you're starting out first, so let's simplify your example a bit:

$conn->write($frame);

$conn->on('data', function ($data) {
    $cpr = new ContProtocol;
    $cpr->readMessage($data);
});

$conn->on('data', function ($data) {
    $cpr = new ContProtocol;
    $cpr->readMessage($data);
});

This will send a single message ($frame) and will wait for the data twice. This means that every time your connection receives some data, both data handlers will be invoked with the same data from the stream.

The way I understand your problem, you only want to attach a single data handler. Then, parse this as a continuous stream with some delimiter between individual messages. For instance, you can use a newline delimiter between message so each single line can be read as a JSON structure with https://github.com/clue/reactphp-ndjson.

The same logic also applies to binary protocols (look up message framing for more details). If you can tell us more about the protocol you're using, we might be able to help you.

Additionally, the time_nanosleep() function must not be used in a truly non-blocking application. I suppose this was only left here for testing purposes, but keep in mind that this will block your entire loop. It looks like this can be removed, but if you want to "wait", use the $loop->addTimer() method instead.

I'll assume this is resolved and will close this for now, please feel free to report back otherwise 👍

from reactphp.

Tick007 avatar Tick007 commented on June 13, 2024

Hello clue, thank you for your answer.
Doesn't $loop2->stop(); should stop wait for new data receiving on open socket connection ?
So my goal was to make analog of following code:
$pop_conn = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp')); socket_connect ( $pop_conn , $dstip, $dstport ); foreach ($arr as $num => $frame) { socket_write($pop_conn, $frame ); time_nanosleep(0, 001000000); $data = socket_read ($pop_conn, 4048); $cpr = new ContProtocol; $cpr->readMessage($data); $cps[$cpr->hdr['UnitNum'][2]] = $cpr; } socket_close ($pop_conn);
ContProtocol, that I use - is some binary protocol, is not JSON. It has it own HEADER and END, and it is not very comfortable to separate single frame from common stream. Much easer to receive individual messages with single frame. Code above do that job. My project is some simulator, where one part receives binary data, repack it to json (with nessesary aditions) and sends to websocket. Websoket works fine, thanks, but another part is expiriences some trouble :)

from reactphp.

clue avatar clue commented on June 13, 2024

@Tick007 I understand where you're coming from. The problem with streaming protocols is this: If you send "hello" and "world" as two "messages", there's no guarantee the receives sees these exact message boundaries, it may as well receive "helloworld" as a single message or "h" and "elloworld" or any combination thereof. That's why you need to employ message framing to avoid this situation.

This is nothing specific to this project, but how the underlying transport mechanisms work (for good reason).

You can also introduce a small delay between each message, which makes it more likely you'll receive each message after another, but depending on your load and/or message size, it's not something you can rely on and you're back to square one. Even if it does work, it's effectively limiting your throughput and increasing latency.

If your protocol is strictly following request/response semantics and you don't want to take advantage of pipelining (sending multiple request messages at once without having to wait for the first response), you may also design this to be strictly sequential. In this case, you can send a single request message, wait for the response and only then send the next request message. This guarantees you're receiving full messages between each step, but you're missing out on the huge I/O improvements pipelining can give you 👍

from reactphp.

Tick007 avatar Tick007 commented on June 13, 2024

Looks like i got you:
` $loop2 = React\EventLoop\Factory::create();
$connector2 = new React\Socket\Connector($loop2);
$cps=null;
echo '100 request'."\n\r";
$connector2->connect($dstip . ':' . $dstport)->then(
function (React\Socket\ConnectionInterface $conn) use ($loop2, &$arr, &$cps) {

                $conn->on('data', function ($data) use ($conn, $loop2, &$cps) {
                    
                    $cpr = new ContProtocol;
                    $cpr->readMessage($data);
                    $cps[$cpr->hdr['UnitNum'][2]] = $cpr;
                    //echo mb_strlen($data);
                    //echo "\n\r";
                }, function (Exception $exception) use ($loop2) {
                    echo "Cannot data connect to server: " . $exception->getMessage();
                    $loop2->stop();
                });
                
                
                foreach ($arr as $num => $frame)  {
                    $loop2->addTimer(0.1, function () use ($conn, $frame) {
                        $conn->write($frame);
                    });
                }
                
                $loop2->addTimer(1, function () use ($loop2) {
                    $loop2->stop();
                 });
            });
        $loop2->run();`

Works way faster than socket_creatr etc...
Thank you.

from reactphp.

Tick007 avatar Tick007 commented on June 13, 2024

May be you should add this to docs....

from reactphp.

clue avatar clue commented on June 13, 2024

Happy to hear you're making some progress!

foreach ($arr as $num => $frame)  {
    $loop2->addTimer(0.1, function () use ($conn, $frame) {
        $conn->write($frame);
    });
}

Note that this piece of code will probably not work the way you may expect it to work. Assuming you have 100 entries in your array, it will start 100 timers which all trigger at around the same time in 100ms. This means a single timer would pretty much do the same thing. I would even question if this timer is needed at all (depends on your use case of course)?

Additionally, as per https://github.com/reactphp/event-loop#addtimer there is no guarantee that timers that are scheduled to trigger at the same time will actually execute in order. This means the writing the second chunk might as well happen before writing the first chunk from your array (which may or may not be a problem for your use case).

If you're sure you need timers in here (which I would question), I would suggest scheduling each timer with an interval of 0.1 * $num so that the array position is taken into account (assuming its a vector/list here).

$conn->on('data', function ($data) use ($conn, $loop2, &$cps) {
      // …
}, function (Exception $exception) use ($loop2) {
    echo "Cannot data connect to server: " . $exception->getMessage();
    $loop2->stop();
});

Note that as per https://github.com/reactphp/stream#data-event, this event handler only accepts a single function. The second function has no effect. It looks like this is supposed to handle failed connections attempts, so this should be added as a second function to the connection promise instead 👍

May be you should add this to docs....

We're happy to accept PRs if you feel there's anything that we can improve in our documentation! :shipit:

from reactphp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.