gpt4 book ai didi

python - 如何让两个程序相互通信

转载 作者:太空宇宙 更新时间:2023-11-04 03:47:10 24 4
gpt4 key购买 nike

我正在涉足 Python 中的网络和多线程。我已经阅读了有关 concurrent.futures 和 SocketServer 的文档,并试图在我正在处理的示例中使用它们。文档中的示例似乎足够直截了当,但我正在努力将它们应用到我正在处理的示例中。

例子如下。 2 个 GUI 应用程序,一个通过用户交互向另一个发送信息,另一个显示此信息。

到目前为止,我已经启动并运行了 2 个应用程序。应用程序 A 让服务器在单独的线程中运行。应用程序 B 能够连接到服务器并发送所需的信息。

在这一点上,我似乎无法找到一种很好的方法来获取应用程序 A 的 GUI 中显示的信息。我可以想到几种 hacky 方法,但我对最好/最 pythonic 的方法感兴趣。这似乎是一个常见问题,因此必须在此处使用通用模式。所以我的问题是。

  • 当服务器运行时,如何从自定义请求处理程序获取信息到服务器。
  • 如何在运行时从线程获取信息到主应用程序?

示例代码如下

服务器窗口

import SocketServer
import concurrent.futures
import sys
from PyQt4 import QtGui

HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)


class MyRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
print('...connected from:', self.client_address)
data = self.rfile.readline().strip()
print('Data from client %s' % data)

class ServerWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setGeometry(1500, 100, 500, 500)

self._control = QtGui.QWidget()
self.setCentralWidget(self._control)

l = QtGui.QVBoxLayout(self._control)
t = QtGui.QTextEdit()
l.addWidget(t)

self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
self.startServerThread()

self.show()

def startServerThread(self):
self.executor.submit(self.startServer)

# How to get information from the thread while it is still running?

def startServer(self):
print('starting server')
tcpServ = SocketServer.TCPServer(ADDR, MyRequestHandler)
print('waiting for connection...')
tcpServ.serve_forever()

# How to get information from the client (custom request handler)
# back to the GUI in a thread safe manner?

def launch():
app = QtGui.QApplication(sys.argv)
ex = ServerWindow()
sys.exit(app.exec_())

if __name__ == '__main__':
launch()

客户端窗口

import socket
import sys
import functools
from PyQt4 import QtGui

HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)

class ClientWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setGeometry(1500, 650, 500, 500)

self._control = QtGui.QWidget()
self.setCentralWidget(self._control)

l = QtGui.QVBoxLayout(self._control)
for i in range(5):
name = 'test %d' % i
b = QtGui.QPushButton(name)
l.addWidget(b)
b.pressed.connect(functools.partial(self.onButtonClick, name))

self.show()

def onButtonClick(self, buttonName):
print('connecting to server')
tcpCliSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpCliSock.connect(ADDR)
print('Sending name %s' % buttonName)
tcpCliSock.send(buttonName)
tcpCliSock.close()


def launch():
app = QtGui.QApplication(sys.argv)
ex = ClientWindow()
sys.exit(app.exec_())

if __name__ == '__main__':
launch()

最佳答案

因此,我所知道的将数据从线程传输到应用程序的主 GUI 线程的少数方法之一是将数据放入 python Queue 中。此 QueueQThread(支持 Qt 信号和槽的 Qt 线程实现)读取。 QThreadqueue.get() 进行阻塞调用。当您的handle() 方法将数据放入Queue 时,QThread 解除阻塞,从队列中读取数据,并发出一个GUI 线程的线程安全信号。作为演示,我将数据添加到 QTextEdit 中。

所以基本上你需要一个 python 线程和 Qt GUI 之间的中介,它通常通过信号/插槽进行交互。 QThread 执行此任务,将线程安全的 Queue 对象与线程安全的 qt 信号发射链接起来。

这实际上遵循了我给出的类似答案 here ,但在这里您有一个套接字而不是一个将数据放入队列的自定义线程。

您可能还对 this 感兴趣SO post,这解释了为什么我用来制作 QThread 和连接信号等的一些代码行是按照它们的顺序编写的!

附言我添加了一行以在应用程序窗口关闭时关闭套接字服务器(套接字服务器用于在后台保持运行)

服务器窗口代码

import SocketServer
import concurrent.futures
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from Queue import Queue

HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)

# create a global queue object that both the handle() method and the QThread (see later in the code) can access
queue = Queue()

class MyRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
print('...connected from:', self.client_address)
data = self.rfile.readline().strip()
print('Data from client %s' % data)
queue.put(data)

class ServerWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setGeometry(1500, 100, 500, 500)

self._control = QtGui.QWidget()
self.setCentralWidget(self._control)

l = QtGui.QVBoxLayout(self._control)
self.t = QtGui.QTextEdit()
l.addWidget(self.t)

self.executor = futures.ThreadPoolExecutor(max_workers=1)
self.startServerThread()

self.show()

@QtCore.pyqtSlot(str)
def receive_data(self, data):
self.t.moveCursor(QtGui.QTextCursor.End)
self.t.insertPlainText( data )

def startServerThread(self):
self.executor.submit(self.startServer)

# How to get information from the thread while it is still running?

def startServer(self):
print('starting server')
self.tcpServ = SocketServer.TCPServer(ADDR, MyRequestHandler)
print('waiting for connection...')
self.tcpServ.serve_forever()

# How to get information from the client (custom request handler)
# back to the GUI in a thread safe manner?

# This class runs in a QThread and listens on the end of a queue and emits a signal to the GUI
class MyReceiver(QtCore.QObject):
mysignal = QtCore.pyqtSignal(str)

def __init__(self,queue,*args,**kwargs):
QtCore.QObject.__init__(self,*args,**kwargs)
self.queue = queue

@QtCore.pyqtSlot()
def run(self):
while True:
text = self.queue.get()
self.mysignal.emit(text)


def launch():
app = QtGui.QApplication(sys.argv)

ex = ServerWindow()

# Create thread that will listen on the other end of the queue, and send the text to the textedit in our application
thread = QtCore.QThread()
my_receiver = MyReceiver(queue)
my_receiver.mysignal.connect(ex.receive_data)
my_receiver.moveToThread(thread)
thread.started.connect(my_receiver.run)
thread.start()

ret_code = app.exec_()
ex.tcpServ.shutdown()
sys.exit(ret_code)

if __name__ == '__main__':
launch()

关于python - 如何让两个程序相互通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23189038/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com