简体   繁体   中英

Can't Use PyQt5 and Eventlet Together

I want to create a SocketIO server in Python on Windows as a simulator for a SocketIO client I'm writing. The server uses eventlet to listen to local port 0.0.0.0. The simulator uses PyQt5 and has two buttons. One button emits one message from the server and the other button emits a different message from the server.

Upon execution, the client connects to the server without issue but the QDialog hangs and the QPushButtons are not displayed.

If I comment out the line that begins with eventlet = then the QDialog displays without issue but [obviously] the client cannot connect to the server.

Any suggestions how I can overcome this issue so that I can connect from the client and also emit server messages by clicking the QPushButtons? Here is my server script:

from PyQt5.QtWidgets import QPushButton, QDialog, QApplication 
import socketio, sys, eventlet

class My_Server(QDialog):

    def __init__(self, parent=None):
        super(My_Server, self).__init__(parent)
        
        self.setWindowTitle("My SocketIO Server")
        self.resize(300,150)
        self.move(300, 200)
        
        self.btn1 = QPushButton(self)
        self.btn1.setText('Msg 1')
        self.btn1.move(50,75)
        self.btn1.clicked.connect(self.send_btn1)
        
        self.btn2 = QPushButton(self)
        self.btn2.setText('Msg 2')   
        self.btn2.move(175,75)
        self.btn2.clicked.connect(self.send_btn2)
        
        self.show()
        
        self.sio = socketio.Server()
        self.serverapp = socketio.WSGIApp(self.sio, static_files={'/': {'content_type': 'text/html', 'filename': 'index.html'}})
        eventlet.wsgi.server(eventlet.listen(('', 5000)), self.serverapp)
        
    def send_btn1(self):
        self.sio.emit('message1', {"Message 1": "Hello"})
        
    def send_btn2(self):
        self.sio.emit('message2', {"Message 2": "World"})

if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = My_Server()
    form.show()
    sys.exit(app.exec_())

Use eventlet-pyqt to spawn greenlets which hold server and other networking operations.

import socketio, sys, eventlet
from hgoldfish.utils import eventlet as eventlet_pyqt

class My_Server(QDialog):
    def __init__(self, parent=None):
        # anything you do previously
        self.operations = eventlet_pyqt.GreenletGroup()
        self.operations.spawn(self.serve)

    def serve(self):
        self.sio = socketio.Server()
        self.serverapp = socketio.WSGIApp(self.sio, static_files={'/': {'content_type': 'text/html', 'filename': 'index.html'}})
        eventlet.wsgi.server(eventlet.listen(('', 5000)), self.serverapp)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = My_Server()
    form.show()
    sys.exit(eventlet.start_application(quitOnLastWindowClosed = True))

my solution for socketio on pyqt5 threading.I couldn't convert socketio server to the class but it is working like that anyway..

i have 2 pyqt5 gui both for for server and client device and both gui he socketio threads to communicate each other both pyqt files depending on.ui files which is not included here fell free to remove them

SocketServer.py


import eventlet
import socketio

sio = socketio.Server()
app = socketio.WSGIApp(sio)



def get_device_id(environ):
    return environ.get('HTTP_DEVICE_ID', None)


@sio.event
def connect(sid, environ):
    device_id = get_device_id(environ) or sid
    sio.save_session(sid, {'device_id': device_id})
    print('{} is connected'.format(device_id))

# this function run on demand
@sio.on('send')
def send(sid, data):
    session = sio.get_session(sid)
    print('Received data from {}: {}'.format(session['device_id'], data))
    sio.emit('receive', {'page': 'main', 'camera': True, 'capture': False,
             'scan': False, 'cpu': 35, 'battery_1': 7.32, 'battery_2': 3.5})

# this function running real time
@sio.on('talk')
def talk(sid):
    session = sio.get_session(sid)
    # print('Received -> Sent to {}'.format(session['device_id']))
    sio.emit('listen', {'page': 0, 'cpu_temp': 35, 'battery_1': 7.32, 'battery_2': 3.5, 'camera': True, 'capture': False,
             'scan': False,'think':True,'talk':False,'speak':False})


@sio.event
def disconnect(sid):
    print('disconnect ', sid)
    
def run():
    print("Server Started")
    eventlet.wsgi.server(eventlet.listen(
        ('192.168.2.19', 5000)), app, log_output=False)

#use when you need to run standalone
# if __name__ == '__main__':
#     print("Server Started")
#     eventlet.wsgi.server(eventlet.listen(
#         ('192.168.2.19', 5000)), app, log_output=False)

PyQt5.py file

import SocketServer as Server
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class ServerThread(QThread):
    server = Server
    def __init__(self, parent=None):
        super().__init__(parent)
       
    def run(self):
        self.server.run()
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.resize(640, 480)

        self.centralwidget = QWidget(self)
        self.setCentralWidget(self.centralwidget)

        VBL = QVBoxLayout(self.centralwidget)
        VBL.setContentsMargins(0, 0, 0, 0)
        VBL.addWidget(self.topbar)

        self.screens = QStackedLayout()
        VBL.addLayout(self.screens)
       
        self.worker = ServerThread()
        self.worker.start()


if __name__ == "__main__":
    App = QApplication(sys.argv)
    App.setStyle('Breeze')
    Root = MainWindow()
    Root.show()
    sys.exit(App.exec())

Client.py file

import sys
from xmlrpc.client import boolean
from PyQt5.QtWidgets import QMainWindow, QFileDialog, QTableWidgetItem, QMessageBox, QApplication
from PyQt5.QtCore import QThread, QTimer, pyqtSlot
from PyQt5.QtGui import QPixmap
from PyQt5 import QtCore
from PyQt5 import uic

import socketio
import time

ui_form = uic.loadUiType("UI_client.ui")[0]


class SocketClient(QThread):
    add_log = QtCore.pyqtSignal(object)
    dataUpdate = QtCore.pyqtSignal(object)
    connStatus = QtCore.pyqtSignal(bool)
    sio = socketio.Client()

    def __init__(self, parent=None):
        super().__init__()
        self.main = parent
        self.ip = '192.168.2.19'
        self.port = 5000
        self.host = 'http://%s:%s' % (self.ip, self.port)

    def set_host(self, ip, port):
        self.ip = ip
        self.port = port

    def run(self):
        self.connect(self.host)

    def connect(self, host):
        SocketClient.sio.on('receive', self.receive)
        SocketClient.sio.on('listen', self.listen)
        try:
            SocketClient.sio.connect(host)
            self.connStatus.emit(True)
            self.add_log.emit('Connection to the server has been completed.')
        except socketio.exceptions.ConnectionError as err:
            self.add_log.emit('Server not found! Try again...')
            self.connStatus.emit(False)
        else:
            pass

    # real time
    def talk(self):
        if not SocketClient.sio.connected:
            self.connect(self.host)
        try:
            SocketClient.sio.emit('talk')
        except:
            self.connStatus.emit(False)

    # real time
    def listen(self, msg):
        if msg:
            self.connStatus.emit(True)
            # this data will process
            self.dataUpdate.emit(msg)
        else:
            self.connStatus.emit(False)

    # on demand
    def send(self, msg):
        try:
            SocketClient.sio.emit('send', msg)
            self.add_log.emit('[Me]:%s' % (msg))
        except:
            self.add_log.emit('[Server] %s' %
                              ("Cant send message to server"))
    # on demand

    def receive(self, msg):
        if msg:
            self.add_log.emit('[Server] %s' % (msg))
        else:
            self.add_log.emit('[Server] %s' %
                              ("server message  is empty !"))


class ChatWindow(QMainWindow, ui_form):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        # fill inputs for test
        self.INPUT_ip.setPlainText("192.168.2.19")
        self.INPUT_port.setPlainText("5000")
        self.BTN_send.setDisabled(True)
        self.BTN_disconnect.hide()
        self.BTN_send.clicked.connect(self.send_message)
        self.BTN_connect.clicked.connect(self.socket_connection)
        self.BTN_disconnect.clicked.connect(self.socket_quit)
        self.connStatus = False
        self.flipImage = 0
        self.sc = SocketClient(self)
        self.timer = QTimer()
        self.timer.timeout.connect(self.realtime_comminication)

        self.sc.add_log.connect(self.add_chat)
        self.sc.dataUpdate.connect(self.read_values)
        self.sc.connStatus.connect(self.enable_send_button)

    def enable_send_button(self, status):
        self.connStatus = status
        if status:
            self.BTN_disconnect.show()
        else:
            self.BTN_disconnect.hide()
        self.BTN_send.setEnabled(status)
        self.CONNECTION_BAR.setEnabled(not status)
        self.LED_connect.setPixmap(
            QPixmap('icons/led-green-on.png' if status else 'icons/led-red-on.png'))
        self.LED_rx_tx.setPixmap(QPixmap(
            'icons/rx-tx-on.png' if (self.flipImage % 2) == 0 else 'icons/rx-tx.png'))
        self.flipImage += 1

    def read_values(self, data):
        for key, value in data.items():
            # set LED status
            led = "LED_"+key
            if hasattr(self, led):
                led = getattr(self, led)
                if value:
                    led.setPixmap(QPixmap('icons/led-green-on.png'))
                else:
                    led.setPixmap(QPixmap('icons/led-red-on.png'))
            # set Button Status
            button = "BTN_"+key
            if hasattr(self, button):
                getattr(self, button).setChecked(value)
            reading = "VALUE_"+key
            if hasattr(self, reading):
                getattr(self, reading).display(value)
            if key == "page":
                switcher = ["BTN_main",
                            "BTN_clock",
                            "BTN_weather"]
                for index, name in enumerate(switcher):
                    led = getattr(self, "LED_page_"+str(index))
                    if index == value:
                        getattr(self, switcher[index]).setChecked(True)
                        led.setPixmap(QPixmap('icons/led-green-on.png'))
                    else:
                        getattr(self, switcher[index]).setChecked(False)
                        led.setPixmap(QPixmap('icons/led-red-on.png'))
                # setattr(self, value, True if value else False)

    def socket_connection(self):
        ip = self.INPUT_ip.toPlainText()
        port = self.INPUT_port.toPlainText()

        if (not ip) or (not port):
            self.add_chat('The ip or port number is empty.')
            return

        self.sc.set_host(ip, port)

        if not self.connStatus:
            self.sc.start()
            self.timer.start(500)

    def socket_quit(self):
        sys.exit()

    def realtime_comminication(self):
        self.sc.talk()

    def send_message(self):
        if not self.connStatus:
            self.add_chat('Connection Lost!...')
            return

        msg = self.INPUT_message.toPlainText()
        self.sc.send(msg)
        self.INPUT_message.setPlainText('')

    @pyqtSlot(object)
    def add_chat(self, msg):
        self.chats.appendPlainText(msg)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWindow = ChatWindow()
    myWindow.setWindowTitle('Remote Command')
    myWindow.show()
    app.exec_()

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