python - PyQt 中的服务器-客户端连接

标签 python sockets pyqt pyqt5

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

代码:

GUI 由设计师创建。

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 小时)。因此,一个小小的演练可以让您再次走上正确的道路,自己完成接下来的几个步骤。

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

    3a。进程 1 运行 main app;

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

    3c。外包其他耗时超过 1-2 秒的任务(在主 GUI 中显示为“卡住”)。

  4. Dialog.py => MyMainAppNameisNOtDialog.py(避免脚本代码中的混淆/拼写错误)

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

服务器端(修改 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 脚本:

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.

关于python - PyQt 中的服务器-客户端连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48499713/

相关文章:

c++ - 使用 winsock 进行文件传输 (c++)

python - Python的decode() 'utf-8'编解码器无法解码位置0 : invalid start byte的字节0xff

qt - 如何在 Qt/PyQt/PySide QLabel 中右对齐富文本 (HTML)?

python - 在 python 中运行时将数据从 GUI 传递到线程

python - 如何将菜单栏添加到 QWidget?

python - 如何将请求上下文重定向到 Django 中的另一个 url

python - 如何使用python从int中获取每个Xbit

c - 无法通过 C 中的套接字通过写入和读取函数发送 char 数组

python - Pyramid_simpleform 可以与 python3.5.2 一起使用吗?

python - 使用 matplotlib 更改 python 条形图中日期时间数据的 x 轴刻度标签的频率