简体   繁体   中英

pyzmq with qt event loop

I'm using pyzmq in my qt app.

I found some past solution in mailinglist in first link . So, here is my code with link.

import zmq
from PyQt5.QtCore import QSocketNotifier
from PyQt5.QtWidgets import QApplication, QWidget


class ChatApp(QWidget):
    def __init__(self):
        super(ChatApp, self).__init__()

        self._zmq_context = zmq.Context()
        self._zmq_sock = self._zmq_context.socket(zmq.SUB)
        self._zmq_sock.connect("tcp://localhost:5556")
        self._zmq_sock.setsockopt(zmq.SUBSCRIBE, b"bm_chat")

        self.read_noti = QSocketNotifier(self._zmq_sock.getsockopt(zmq.FD),
                                             QSocketNotifier.Read,
                                             self)
        self.read_noti.activated.connect(self.on_read_msg)

    def on_read_msg(self, _):
        self.read_noti.setEnabled(False)
        flags = self._zmq_sock.getsockopt(zmq.EVENTS)

        if flags & zmq.POLLIN:
            msg = self._zmq_sock.recv_multipart()
            topic = msg[0]
            data = msg[1]
            print(topic, data)
        elif flags & zmq.POLLOUT:
            print("[Socket] zmq.POLLOUT")
        elif flags & zmq.POLLERR:
            print("[Socket] zmq.POLLERR")
        else:
            print("[Socket] FAILURE")
        self.read_noti.setEnabled(True)

if __name__ == '__main__':
    app = QApplication([])
    win = ChatApp()
    win.show()
    app.exec_()

But, as expected after message fire once, and never happend again. This is my message

[Socket] FAILURE
b'bm_trade' b'hello0'

So I searched other solutions here , with read self._zmq_sock.getsockopt(zmq.EVENTS) after qt notification enabled. So I changed my code in last line

def on_read_msg(self, _):
    self.read_noti.setEnabled(False)
    flags = self._zmq_sock.getsockopt(zmq.EVENTS)

    if flags & zmq.POLLIN:
        msg = self._zmq_sock.recv_multipart()
        topic = msg[0]
        data = msg[1]
        print(topic, data)
    elif flags & zmq.POLLOUT:
        print("[Socket] zmq.POLLOUT")
    elif flags & zmq.POLLERR:
        print("[Socket] zmq.POLLERR")
    else:
        print("[Socket] FAILURE")
    self.read_noti.setEnabled(True)
    self._zmq_sock.getsockopt(zmq.EVENTS) // Here is fixed      

It works great, until data rate is low. Here is my PUB server code.

from time import sleep

import zmq

context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5557")

def ms(millisec):
    return millisec / 1000

if __name__ == '__main__':
    count = 0
    while True:
        socket.send_multipart(
            [b'bm_trade', bytes(('hello' + str(count)).encode('utf-8'))])
        count += 1

        sleep(ms(10))

That trick is only work on event time gap over 10 ms. If you change sleep(ms()) under 10, client side also get fired once, and never fire.

Someone would say it's okay, but in my app, latency is very low and all message always should visible in gui.

Why this problem happened, how to solve this?

You just have to continue reading while there is data as I show below:

def on_read_msg(self):
    self.read_noti.setEnabled(False)

    if self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLIN:
        while self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLIN:
            topic, data = self._zmq_sock.recv_multipart()
            print(topic, data)
    elif self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLOUT:
        print("[Socket] zmq.POLLOUT")
    elif self._zmq_sock.getsockopt(zmq.EVENTS) & zmq.POLLERR:
        print("[Socket] zmq.POLLERR")

    self.read_noti.setEnabled(True)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM