Reputation: 225
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?
Upvotes: 0
Views: 854
Reputation: 243897
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)
Upvotes: 1