PyQt 中的服务器-客户端连接 [英] Server-client connection in PyQt

查看:158
本文介绍了PyQt 中的服务器-客户端连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 PyQt 中编写一个可以处理服务器-客户端连接(1:1 连接就足够了)的 simpe 程序.我能够编写套接字部分,但使用 GUI 我不知道.我只想有 2 个对话框,一个用于服务器,一个用于客户端(非常简单,只有 1 个用于发送的按钮和一个用于键入消息的文本字段).我想从服务器向客户端发送一条消息,然后用另一条消息回复服务器.你知道如何开始吗?或者可能是示例代码?谢谢

I would like to write a simpe program that can handle a server-client connection (1:1 connection is enough) in PyQt. I was able to write the socket part but with the GUI I have no idea. I just want to have 2 dialogs one for the server and one for the client(very simple, only 1 button for sending and a textfield to type the message). I want to send a message from the server to the client and then reply to server with another message. Do you have any idea how to begin? Or maybe a sample code? Thank you

代码:

GUI 由设计师创建.

The GUI was created by the Desginer.

from PyQt5 import QtCore, QtWidgets
class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(353, 266)
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(20, 30, 47, 13))
        self.label.setObjectName("label")
        self.pushButton = QtWidgets.QPushButton(Dialog)
        self.pushButton.setGeometry(QtCore.QRect(80, 110, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.textEdit = QtWidgets.QTextEdit(Dialog)
        self.textEdit.setGeometry(QtCore.QRect(80, 20, 141, 71))
        self.textEdit.setObjectName("textEdit")

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.label.setText(_translate("Dialog", "Message:"))
        self.pushButton.setText(_translate("Dialog", "Send"))

这是对话框类:

class Dialog(QDialog, Ui_Dialog):

    def __init__(self,socket):
        super(Dialog, self).__init__()
        self.setupUi(self)
        self.socket = socket

    def send(self):
        message = self.textEdit.toPlainText()
        self.socket.send(message.encode())

服务器类:

class Server():
    def __init__(self):
        host = socket.gethostname()
        port = 5000
        server_socket = socket.socket()
        server_socket.bind((host, port))
        server_socket.listen(2)
        conn, address = server_socket.accept()
        print("Connection from: " + str(address))

        gui = Dialog(server_socket)
        gui.show()
        while True:
            data = conn.recv(1024).decode()
            if not data:
                break
            print("message: " + str(data))
        conn.close()

if __name__ == '__main__':
    server = Server()

客户端类:

class Client():
    def __init__(self):
        host = socket.gethostname()
        port = 5000
        client_socket = socket.socket()
        client_socket.connect((host, port))
        gui = Dialog(client_socket)
        gui.show()
        message = ""

        while message.lower().strip() != 'bye':

            data = client_socket.recv(1024).decode()
            print('message: ', data)

        client_socket.close()

if __name__ == '__main__':
    client = Client()

推荐答案

为了简单起见:

您的问题的结果是花费了大量的编码时间(大约 2-3 小时).因此,这是一个小小的演练,可让您再次走上正确的道路,自己完成接下来的几步.

The resultant of your question is spending a lot of coding time (approx. 2-3 hours). Thus a tiny walk-through to get you on the right path again to do the next few steps yourself.

  1. 在这种情况下,您的 main 程序文件是 Dialog.py 而不是 Client.py.
  2. 如果你构建/编译你的程序 Client.py 要么是 client.pyd 要么是另一种形式的库.在 Windows 上 Dialog 将是一个可执行文件.
  3. 将 Client.py 重命名为 LOGIN_GUI 或其他与本地登录"功能相关的名称,因为这就是您要完成的任务.使用名称 client.py 进行远程日志记录(与服务器不同的 GUI!).3.在对话框中使用pythons multiprocessing.

  1. Your main program file in this case is Dialog.py and not Client.py.
  2. If you build/compile your program Client.py is either client.pyd or another form of library. On windows Dialog will be an executable.
  3. rename Client.py into LOGIN_GUI or something that refers to its function of "local login" because that is what you try to accomplish. Use name client.py for remote logging (different GUI than server!). 3.In Dialog use pythons multiprocessing.

3a.进程 1 运行 main app;

3a. Process 1 runs main app;

3b.进程2运行客户端-服务器;

3b. Process 2 runs client-server;

3c.外包其他耗时超过 1-2 秒的任务(在主 GUI 中显示为冻结").

3c. Outsource other tasks taking more than 1-2sec (shows as "freezing" in main GUI).

Dialog.py => MyMainAppNameisNOtDialog.py(避免在脚本代码中出现混淆/错别字)

Dialog.py => MyMainAppNameisNOtDialog.py (avoid confusion/typo's inside your scripting code)

如果您像下面这样编写服务器 ThreadingMixIn 样式,您就可以从两台不同的计算机登录.据我所知,这是 pyqt5 中不可用的工具.另请参阅以下代码中的内联注释.

If you code your server ThreadingMixIn style like below you are able to log-in from two different computers. This is as far as I know not available as tool in pyqt5. See also inline comments inside the below code.

服务器端(pythons的修改Socket-server ThreadingMixIn):

Server-side (modification of pythons Socket-server ThreadingMixIn):

import socket
import threading
import SocketServer

# MyAwesomelyNamedServerScript.py

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):

        def func1(scr1):
            #put code that does something here.
            print 'func1 : %s' % scr1
            return scr1

        def funct2(scr2):
            #put code that does something here.
            print 'func2 : %s' % scr2
            return scr2


        # self.request is the TCP socket connected to the client
        cur_thread = threading.current_thread()
        data = self.request.recv(1024)

        # In the data package the IP from client. 
        # Extract and add to an IP list (e.g. max 2 connection.)
        # if/else statement: if max connection reached than report back "cannot connect... waiting in queue or something".
        # limiting the request also prevent DDos attacks from the start.

        data_proc = func1(data)       # do something once
        data      = func2(data_proc)  # do something twice

        response = "{}: {}".format(cur_thread.name, data)
        self.request.sendall(response)

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass

def setupServer(ip = None, port = None, message = None):
    # Ip, port, message can be linked to below code if you want exernal input via GUI
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "localhost", 0

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print "Server loop running in thread:", server_thread.name
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    try:
        sock.sendall(message)
        response = sock.recv(1024)
        print "Received: {}".format(response)
    finally:
        sock.close()

def test_main():

        #client(ip, port, "Hello World 1")
        #client(ip, port, "Hello World 2")
        #client(ip, port, "Hello World 3")

        client(message = "Hello World 1")
        client(message = "Hello World 2")
        client(message = "Hello World 3")

        server.shutdown()
        server.server_close()

if __name__ == "__main__":

    test_main()  #runs the main test

简而言之 MainApp.py 脚本:

The MainApp.py script in short:

import myloginscript
import myAwesomeMainGUI

...snippet ... <incl. Qt imports, etc.> ...

#MainApp.py

class MyMainUI(QtWidgets.QMainWindow, myAwesomeMainGUI.Ui_MainWindow):

    ...snippet <your code>...

    def setUpass(self, username):
        # do whatever you want with the username
        # if Pword brought here then login.username.text() needs to be altered to get pw instead.
        self.username = username  # this variable shoud be made inside your main code.
#        self.label.setText("Username: %s" % self.username)
        print 'The username is : %s' % self.username

if _name__ = '__main__':

    app.QApplication(sys.argv)

    login= myloginscript()  # this runs your login script (GUI starts if attached therein.)

    if login.exec():
        window = MymainwindowDialog()           # main appwindow...not login GUI.
        window.setUpass(login.username.text())
        window.show()
        sys.stdout.flush()
        try:
            sys.exit(app.exec())
        except:
            print('Exit now.. wrong Uname or Pword')
    else:
        sys.exit(-1)  # user pressed 'Cancel', lets quit the program here.

这篇关于PyQt 中的服务器-客户端连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆