enwi / dartzmq

A simple dart zeromq implementation/wrapper around the libzmq C++ library
https://pub.dev/documentation/dartzmq/latest/
MIT License
26 stars 17 forks source link

Added blocking recv() function #21

Closed augustbering closed 6 months ago

enwi commented 1 year ago

I think this will break how the library works, because messages are expected to be received by the internal poller of the library. We either need a new socket that does not get registered to the poller or change the behavior so that we can wait for a reply received by the poller. Another solution would be to explicitly wait for a message on the message stream of the socket.

augustbering commented 7 months ago

I think this will break how the library works, because messages are expected to be received by the internal poller of the library. We either need a new socket that does not get registered to the poller or change the behavior so that we can wait for a reply received by the poller. Another solution would be to explicitly wait for a message on the message stream of the socket.

Sorry for late reply, completely forgot about this :-) I've used this for some time, and it works fine if you don't "listen" to the incoming messages for that socket. In this function you register the socket for polling:

void _listen(ZSocket socket) { _bindings.zmq_poller_add(_poller, socket._socket, nullptr, ZMQ_POLLIN); _listening.add(socket); }

so I think an easy fix could be that recv() just checks the _listening list and if it contains this socket it throws an error. Sounds sensible?

enwi commented 7 months ago

so I think an easy fix could be that recv() just checks the _listening list and if it contains this socket it throws an error. Sounds sensible?

I think this would be a good option, but then you could also just make a new socket class, which does not get registered and has the recv() function

augustbering commented 7 months ago

Yes, let's see what works best there. But another issue that I've been struggling with, perhaps you have a smart solution:

REQ/REP works nicely against my python server when I just use recv() for reading there, but when I do polling it just breaks down and I get "ZeroMQException(4): EINTR: The operation was interrupted" and "bad state" and such. My python code looks like this in the failing cases:

context = zmq.Context()
zmqsock = context.socket(zmq.REP)

port=5557
zmqsock.bind(f"tcp://*:{port}")
poller=zmq.Poller()
poller.register(zmqsock, zmq.POLLIN)
print(f"Listening on port {port}, outputing to {serialport}")
while running:
    if len(poller.poll(1000))>0:
        message = zmqsock.recv()
        cmd=message.decode()

so there's something this dart/c implementation does that's not compatible with the python poller it seems...

enwi commented 7 months ago

I think I had similar issues, but could not resolve them

enwi commented 7 months ago

I will also push some changes to your branch now, let me know what you think about it

enwi commented 7 months ago

Okay I could not push to your branch, but I pushed my proposal to the dev branch

enwi commented 7 months ago

@augustbering Please take a look at #33 and try out the dev branch and see if the issue is resolved for you :)

augustbering commented 7 months ago

You're pretty fast I must say!

augustbering commented 7 months ago

Seems it behaves just the same, did you make any changes that you expect should have fixed it?

augustbering commented 7 months ago

by the way, if that's any clue, for my use case, when the server is polling, it works even worse when I try using your defualt async "listen" way of reading the responses. No idea why.

enwi commented 7 months ago

@augustbering As long as you do not send a message (Req) before you received the reply (from Rep) there should be no issue. Maybe we should even make a special case for Req/Rep that sending a message always blocks and receives the reply, but that would not work well with flutter, blocking the main thread. That is why I initially used the Poller to async poll incoming data without blocking the main thread.

enwi commented 7 months ago

I guess the best solution to all problems would be having the poller run in a separate thread. In the coming weeks I will try and work on getting that up and running.

augustbering commented 7 months ago

Yes, possibly, but do you think this would resolve the server-poller issue somehow? I could try and run the c-zmq version to see if the issue is somehow related to how dart handles threading. I know zmq creates a bunch of worker threads but I haven't looked at the code.

On Fri, Feb 9, 2024 at 8:44 AM Moritz Wirger @.***> wrote:

I guess the best solution to all problems would be having the poller run in a separate thread. In the coming weeks I will try and work on getting that up and running.

— Reply to this email directly, view it on GitHub https://github.com/enwi/dartzmq/pull/21#issuecomment-1935466122, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJOYLDP5ZL65MUSVJHEGV3YSXHVVAVCNFSM6AAAAAAXTNVV72VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZVGQ3DMMJSGI . You are receiving this because you were mentioned.Message ID: @.***>

augustbering commented 7 months ago

Just tested a simple c program and it works flawlessly against the python server, so there seems to be something in the dart runtime that messes up things. I can't imagine what that could be though.


#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int main (void)
{
    printf ("Connecting to hello world server...\n");
    void *context = zmq_ctx_new ();
    void *requester = zmq_socket (context, ZMQ_REQ);
    zmq_connect (requester, "tcp://localhost:5557");
    zmq_msg_t msg;
    zmq_msg_init(&msg);
    int request_nbr;
    for (request_nbr = 0; request_nbr != 10; request_nbr++) {
        printf ("Sending Hello %d...\n", request_nbr);
        zmq_send (requester, "Hello", 5, 0);
        zmq_msg_recv(&msg, requester, 0);
        void *data=zmq_msg_data(&msg);
        printf ("Received World %d\n", request_nbr);
        sleep (1);          //  Do some 'work'
    }
    zmq_close (requester);
    zmq_ctx_destroy (context);
    return 0;
}
augustbering commented 7 months ago

Tested a few other things too:

Made sure I use the same zmqlib version as my working c sample, no change. Tried running the req/rep in a seperate Isolate. No change....

Damn, I give up!

enwi commented 7 months ago

Figuring this sort of stuff out is always frustrating 😅

enwi commented 6 months ago

I think we can close this pullrequest and open a new issue for the one you are describing?