Does ZeroMQ have a notification/callback event/message for when data arrives?

前端 未结 3 2044
难免孤独
难免孤独 2020-12-19 18:42

I am trying to integrate ZMQ into an existing windows application that relies heavily on MFC sockets (CASyncSocket).

I\'ve got a CWinThread derived UI thread (with

相关标签:
3条回答
  • 2020-12-19 19:12

    You can signal from thread to thread with custom Windows messages. Here is a custom message:

    #define WM_MY_MESSAGE (WM_APP + 1)
    

    To send it to a thread that has a window use PostMessage or SendMessage to the HWND. Add it to the window's message map with ON_MESSAGE.

    To send it to a CWinThread-derived thread that has no windows use PostThreadMessage and receive it with ON_THREAD_MESSAGE.

    0 讨论(0)
  • 2020-12-19 19:28

    You could call zmq_recv() with the ZMQ_NOBLOCK flag inside your app's main message loop by overriding your CWinApp::OnIdle(). zmq_recv will return immediately if there is no data waiting on the socket. If there's data, handle it - but be aware that if you do something slow, you'll make the app unresponsive.

    Edit: I didn't realize that OnIdle only gets called once when the message queue becomes empty. But according to MSDN's documentation, you can return a nonzero value to keep getting called forever:

    1. If the message loop checks the message queue and finds no pending messages, it calls OnIdle and supplies 0 as the lCount argument.
    2. OnIdle performs some processing and returns a nonzero value to indicate it should be called again to do further processing.
    3. The message loop checks the message queue again. If no messages are pending, it calls OnIdle again, incrementing the lCount argument.
    4. Eventually, OnIdle finishes processing all its idle tasks and returns 0. This tells the message loop to stop calling OnIdle until the next message is received from the message queue, at which point the idle cycle restarts with the argument set to 0.

    I also found this thread on GameDev.net where a user said:

    All of the tools I have ever written in MFC that use D3D use the OnIdle() function:

    BOOL CD3DEditorApp::OnIdle(LONG lCount) 
    {
        // Call base class first
        CWinApp:OnIdle( lCount );
    
        // game stuff...
    
        // Always return true - this asks the framework to constantly
        // call the Idle function when it isn't busy doing something
        // else.
        return TRUE;
    }
    

    So, at least according to one person, it's a common technique.

    0 讨论(0)
  • 2020-12-19 19:29

    Ultimately, the answer is no. There are no current callback/notifications for when data arrives in ZeroMQ that you can link into. I was also unable to find any fork that adds this functionality.

    I was unable to get ZMQ working while using the traditional OnReceive calls provide by the MFC socket framework within a single thread and adding a 2nd thread to dedicate to ZMQ defeated the whole purpose for using it (it is being used for thread synchronization).

    My implementation that works ended up dropping MFC sockets and using ZMQ for both my inproc server (for communicating with other thread) as well as my TCP (non-ZMQ) server connection and using a blocking polling call (zmq_poll()) in the OnIdle() method (returning 1 every time to create a busy loop). The blocking poll

    BOOL CMyThreaClass::OnIdle(LONG lCount)
    {
        UNREFERENCED_PARAMETER(lCount);
    
        zmq_pollitem_t items [] = {
        { m_pZMQInprocServer, 0, ZMQ_POLLIN, 0 },
        { m_pZMQTCPSocket, 0, ZMQ_POLLIN, 0 }
        };
        const int iZMQInfiniteTimeout(-1);
        iResult = zmq_poll(&items[0], sizeof(items) / sizeof(items[0]), iZMQInfiniteTimeout);
        TRACE("zmq_poll result: %d\n", iResult);
    
        if (items[0].revents & ZMQ_POLLIN)
        {
            sMyStruct sMessage;
            iResult = zmq_recv(m_pZMQInprocServer, &sMessage, sizeof(sMessage), ZMQ_DONTWAIT); // don't block (the zmq_poll blocks for us)
            TRACE("inproc recv result: %d\n", iResult);
            //  Process inproc messages
            iResult = zmq_send(pZMQInprocServer, &sMessage, sizeof(sMessage), ZMQ_NULL); // block
            TRACE("inproc send result: %d\n", iResult);
        }
        if (items[1].revents & ZMQ_POLLIN)
        {
            // there will be an ZMQ_IDENTITY identifier on the beginning of the socket buffer, read it off first
            uint8_t id [256];
            size_t id_size = 256;
            iResult = zmq_getsockopt(m_pZMQTCPSocket, ZMQ_IDENTITY, id, &id_size);
            TRACE("getsockopt poll result %d:id %d\n", iResult, id);
            iResult = zmq_recv(m_pZMQTCPSocket, &id, id_Size, ZMQ_DONTWAIT); // don't block
            // now get our actual data
            char szBuffer[1024];
            int iBytesReceived = zmq_recv(m_pZMQSocket, szBuffer, sizeof(szBuffer), ZMQ_DONTWAIT);
            if (iBytesReceived > 0)
            {
                // process TCP data
            }
        }
    }
    

    Note: This answer requires using ZMQ 4 or later since earlier versions of ZMQ will not communicate with a regular TCP socket connection.

    0 讨论(0)
提交回复
热议问题