不能同时使用 PyQt5 和 Eventlet



我想在Windows上用Python创建一个SocketIO服务器,作为我正在编写的SocketIO客户端的模拟器。服务器使用eventlet监听本地端口0.0.0.0。模拟器使用PyQt5并有两个按钮。一个按钮从服务器发出一条消息,另一个按钮从服务器发出另一条消息。

执行后,客户端连接到服务器没有问题,但QDialog挂起,QPushButtons不显示。

如果我注释掉以eventlet =开始的行,那么QDialog显示没有问题,但[显然]客户端无法连接到服务器。

有什么建议我可以克服这个问题,这样我就可以从客户端连接,并通过点击QPushButtons发出服务器消息?下面是我的服务器脚本:

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_())

使用eventlet-pyqt生成greenlet来保存服务器和其他网络操作。

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))

我对pyqt5线程的套接字的解决方案。我无法将sockettio服务器转换为类,但它是这样工作的。

我有两个pyqt5 GUI,用于服务器和客户端设备,两个GUI和套接字线程相互通信这两个pyqt文件依赖于.ui文件,这里不包括可以自由删除它们

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文件

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文件

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_()

最新更新