一、twisted与PyQT5事件循环
需要用到TCP服务器,还需要PYQT做界面,网上找了两篇但始终运行不正常,reactor总是阻塞了图形界面。
https://www.cnblogs.com/yueerwanwan0204/p/5589860.html twisted聊天系统
https://www.cnblogs.com/weijy/p/4068714.html 使用PyQt4和twisted写的局域网聊天室
后来看了twisted开发文档,要在twisted事件循环中加入界面的事件循环,需要用到不同的reactor。twisted内置了下列图形界面的reactor。
对于PyQT,需要在github下载qt5reactor,并在设置twisted之前配置好reactor。如果tcpserver需要接收界面的操作指令,并发送到对应的client,需要先把消息发送到tcpserver,再通过server发送到client。
https://github.com/sunu/qt5reactor
Before running / importing any other Twisted code, invoke:
app = QApplication(sys.argv) # your code to init QtCore
from twisted.application import reactors
reactors.installReactor('qt5')
or
app = QApplication(sys.argv) # your code to init QtCore
import qt5reactor
qt5reactor.install()
class MySocket(Protocol):
def __init__(self, parent, users):
self.users = users
self.parent = parent
self.receive_heartbeat_time = 0
self._data_buffer = bytes()
def dataReceived(self, data):
"""
接受到数据以后的操作,省略解析步骤,解析完成后通过parent发送信号到UI
"""
self.parent.SigTcpServerToUi.emit(tcpID, content)
#同时继承Factory和QObject,否则不能用信号
class MyFactory(Factory, QObject):
SigTcpServerToUi= pyqtSignal(int, QbyteArray)
def __init__(self):
super().__init__()
self.users = {}
def buildProtocol(self, addr):
#MySocket继承自protocol
return MySocket(self, self.users )
def check_users_online(self):
#receive_heartbeat_time为7秒内接收从客户端来的心跳消息次数,正常2秒接收一次,如果心跳次数少于2判断客户端的连接断开。
for key, value in self.users.items():
if value.receive_heartbeat_time < 2:
value.transport.abortConnection()
def send_heart_check(self):
#从服务器向客户端发送心跳消息。
for key, value in self.users.items():
value.send_heartbeat()
def sendUiCommand(self, tcpID, command_id, content ):
#界面向指定tcpID的TCP连接发送消息,这里tcpID与客户端的IP关联。
for key, value in self.users.items():
if key == tcpID:
value.send_content(command_id, content)
if __name__ == "__main__":
app = QApplication(sys.argv)
import qt5reactor
qt5reactor.install()
#在qt5reactor.install()之后再导入reactor
from twisted.internet import reactor
print("init UI start")
MyMainUI = MyMainWindow()
MyMainUI.show()
MytcpServer = MyFactory()
#SigTcpServerToUi是服务器到UI的消息,UiToTcpServerSignal是UI到TCP客户端的消息。
MytcpServer.SigTcpServerToUi.connect(MyMainUI.OnClientMessage)
MyMainUI.SigUiToTcpServer.connect(MytcpServer.sendUiCommand)
task1 = task.LoopingCall(MytcpServer.check_users_online)
task1.start(7, now=False)
task2 = task.LoopingCall(MytcpServer.send_heart_check)
task2.start(2, now=False)
reactor.listenTCP(4001, MytcpServer)
reactor.runReturn()
sys.exit(app.exec_())