python-3.x - 在客户端应用程序上将一个套接字与多个窗口一起使用

标签 python-3.x sockets pyqt5

这里的快速问题...(顺便说一句,对不起,如果已经得到回答...)我有一个QDialog窗口(由QMainWindow创建),在其中创建和使用了一个套接字。经过一些操作后,QDialog窗口关闭(通过使用QDialog.accept()命令),然后打开另一个新的QDialog窗口(通过QMainWindow)。从这个新窗口,我希望能够使用已经打开的套接字将信息发送到服务器。

我尝试通过使用以下几行代码来做到这一点:

server = "192.168.100.195"
port = 5555
address = (server, port)
# ----- Some other stuff... ----
socket_de_connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Not using the socket.connect() because the previous QDialog already connected to the server

然后,当我尝试发送邮件时,出现以下错误:
OSError: [ErrnOSError: [Errno 57] Socket is not connected

但是服务器在控制台中向我显示,仍在打开先前在QDialog中创建的套接字(我没有故意关闭它,因为我想继续在程序的多个窗口中使用它。)

有没有办法重用已经打开的套接字通过多个窗口?

顺便说一句,我程序中的每个窗口在单独的文件中都有代码。

编辑:

这里有一些其他信息可以帮助您:

我的第一个QDialog的代码:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QRegExpValidator
import socket
import pickle
import sys
server = "192.168.100.195"
port = 5555


class Verification(QDialog):
    def __init__(self):
        super(Verification, self).__init__()
        self.boite_texte_code = QLineEdit(self)
        self.bouton_verifier = QPushButton(self)
        self.bouton_annuler2 = QPushButton(self)
        self.invite_code = QLabel(self)
        self.accept_local_test = "Ok"
        self.regex2 = QRegExp()
        self.validator2 = QRegExpValidator()
        self.msg = QMessageBox()
        self.socket_de_connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.init_ui()

    def init_ui(self):

        address = (server, port)
        self.socket_de_connexion.connect(address)
        # print(self.socket_connexion)
        self.resize(290, 110)
        self.center()
        self.setWindowTitle("Veuillez saisir le code d'invitation:")
        self.regex2 = QRegExp("^[0-9]{4}")
        self.validator2 = QRegExpValidator(self.regex2)
        self.boite_texte_code.setValidator(self.validator2)
        self.boite_texte_code.setGeometry(150, 20, 100, 25)
        self.bouton_annuler2.setText("Annuler")
        self.bouton_annuler2.setGeometry(157, 60, 100, 40)
        self.bouton_annuler2.clicked.connect(self.annuler2)
        self.bouton_verifier.setDefault(True)
        self.bouton_verifier.setEnabled(False)
        self.bouton_verifier.setText("Confirmer")
        self.bouton_verifier.setGeometry(57, 60, 100, 40)
        self.bouton_verifier.clicked.connect(self.confirmer2)
        self.invite_code.setText("Code d'invitation:")
        self.invite_code.adjustSize()
        self.invite_code.move(30, 25)
        self.boite_texte_code.textChanged.connect(self.texte_change)

    def center(self):
        # SOME OTHER CODE NOT NEEDED FOR THIS QUESTION

    def annuler2(self):
        self.socket_de_connexion.close()
        self.close()

    def confirmer2(self):
        print("Trying to send informations to server...")
        msg = self.socket_de_connexion.recv(2048)
        message = pickle.loads(msg)
        print(message)
        if message == "Connecté!":
            print("in...")
            data_to_send = pickle.dumps("join")
            self.socket_de_connexion.send(data_to_send)
            verif_pickled = self.socket_de_connexion.recv(2048)
            verif = pickle.loads(verif_pickled)
            if verif == "code?":
                print("asked")
                code_to_send = pickle.dumps(self.boite_texte_code.text())
                self.socket_de_connexion.send(code_to_send)
                answer_pickled = self.socket_de_connexion.recv(2048)
                answer = pickle.loads(answer_pickled)
                print(answer)
                if answer == "No":
                    print("Oups!")
                    self.msg.setIcon(QMessageBox.Critical)
                    self.msg.setText("Erreur! Le code est invalide!")
                    self.msg.setInformativeText(
                        "Veuillez vérifier la validité du code. Le programme va maintenant quitter.")
                    self.msg.setWindowTitle("Oups!")
                    self.msg.setStandardButtons(QMessageBox.Ok)
                    self.msg.exec_()
                    # add msg box here
                    # self.close()
                    # socket_de_connexion.shutdown()
                    # socket_de_connexion.close()
                    sys.exit()
                elif answer == "Yes":
                    print("yes")
                    #return self.socket_de_connexion
                    self.accept()
        if self.accept_local_test == "Ok":
            if self.boite_texte_code.text() != "":
                pass
                # self.accept()
        else:
            print("Nope!")

    def texte_change(self):
        # SOME OTHER CODE NOT NEEDED FOR THIS QUESTION


if __name__ == '__main__':
    app = QDialog()
    verification = Verification()
    verification.show()
    app.exec_()

这是我在另一个文件中的第二个QDialog:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import jeu
import socket
import pickle
server = "192.168.100.195"
port = 5555
address = (server, port)


class JoinPartie(QDialog):
    def __init__(self):
        super(JoinPartie, self).__init__()
        self.socket_de_connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.une_partie = None
        self.code = int
        self.setWindowTitle("Veuillez remplir les éléments suivants")
        self.boite_texte_username = QLineEdit(self)
        self.regex = QRegExp("^\w[\w|\s|\.]+")
        self.validator = QRegExpValidator(self.regex)
        self.boite_texte_username.setValidator(self.validator)
        self.bouton_creer = QPushButton(self)
        self.bouton_annuler = QPushButton(self)
        self.invite_username = QLabel(self)
        self.invite_couleur = QLabel(self)
        self.choix_de_couleur = QComboBox(self)
        self.init_ui()

    def init_ui(self):
        # --------------- Paramètres de la fenêtre --------------------
        self.resize(640, 325)
        self.center()
        self.invite_username.setText("Nom d'utilisateur à afficher durant la partie: ")
        self.invite_couleur.setText("Veuillez choisir une couleur:")
        self.invite_username.adjustSize()
        self.invite_couleur.adjustSize()
        self.invite_username.move(30, 75)
        self.invite_couleur.move(30, 120)
        self.boite_texte_username.setGeometry(300, 70, 300, 25)
        self.bouton_annuler.setText("Annuler")
        self.bouton_annuler.setGeometry(530, 275, 100, 40)
        self.bouton_annuler.clicked.connect(self.annuler)
        self.bouton_creer.setDefault(True)
        self.bouton_creer.setText("Confirmer")
        self.bouton_creer.setGeometry(430, 275, 100, 40)
        self.bouton_creer.setEnabled(False)
        self.bouton_creer.clicked.connect(self.confirmer)
        self.choix_de_couleur.setGeometry(307, 115, 300, 25)
        self.choix_de_couleur.addItems(["Couleur 1", "Couleur 2", "Couleur 3"])
        self.boite_texte_username.textChanged.connect(self.texte_change)

    def texte_change(self):
        # SOME CODE NOT NEEDED FOR THIS QUESTION

    def center(self):
        # SOME CODE NOT NEEDED FOR THIS QUESTION

    def annuler(self):
        self.close()

    def confirmer(self):
        test = pickle.dumps("test'")
        self.socket_de_connexion.send(test) # --> HERE IT FAILS TO SEND, GIVING ME THE ERROR MESSAGE MENTIONNED ABOVE
        self.accept()
        if not self.isVisible():
            self.une_partie = jeu.Jeu(2, self.boite_texte_username.text(),  self.choix_de_couleur.currentText())
            self.une_partie.show()


if __name__ == '__main__':
    app = QDialog()
    join_partie = JoinPartie()
    join_partie.show()
    app.exec_()

这是服务器端的代码:
import socket
import pickle
import random
from _thread import *
games = {}
couleurs = ["Bleu", "Rouge", "Jaune", "Vert"]
paquet_de_carte_initial = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
                           3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
                           5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
                           7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
                           9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
                           11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
                           12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
                           "SB", "SB", "SB", "SB", "SB", "SB", "SB", "SB", "SB", "SB", "SB", "SB"]
server = "192.168.100.195"
port = 5555
socket_de_connexion = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


def code_invitation():
    print("")
    digit1 = random.choice('0123456789')  # Chooses a random element
    digit2 = random.choice('0123456789')
    digit3 = random.choice('0123456789')
    digit4 = random.choice('0123456789')
    code = digit1 + digit2 + digit3 + digit4
    games[code] = {}
    print(games)
    return code


def split_cards(nbre):
    print("in")
    random.shuffle(paquet_de_carte_initial)
    random.shuffle(paquet_de_carte_initial)
    random.shuffle(paquet_de_carte_initial)
    print(paquet_de_carte_initial)
    if nbre == 2:
        print(2)
        player0 = []
        player1 = []
        main0 = []
        main1 = []
        for i in range(30):
            player0.append(paquet_de_carte_initial[0])
            paquet_de_carte_initial.pop(0)
            player1.append(paquet_de_carte_initial[0])
            paquet_de_carte_initial.pop(0)
        # print(player0)
        # print(player1)
        for j in range(5):
            main0.append(paquet_de_carte_initial[0])
            paquet_de_carte_initial.pop(0)
            main1.append(paquet_de_carte_initial[0])
            paquet_de_carte_initial.pop(0)
        # print(main0)
        # print(main1)
        # print(paquet_de_carte_initial)
        setup = (player0, main0, player1, main1, paquet_de_carte_initial)
        return setup


try:
    socket_de_connexion.bind((server, port))
except socket.error as e:
    str(e)

socket_de_connexion.listen(4)
print("Le server a démaré. \n En attente d'une connexion...")


def threaded_client(conn):
    msg = pickle.dumps("Connecté!")
    conn.send(msg)
    while True:
        try:
            data_recu = conn.recv(2048)
            data = pickle.loads(data_recu)
            print(data)
            if data == "create":
                print("création d'un code d'invitation...")
                code_cree = code_invitation()
                print(code_cree)
                code_pickled = pickle.dumps(code_cree)
                conn.send(code_pickled)
                joueurs = conn.recv(2048)
                info_joueurs = pickle.loads(joueurs)
                print(info_joueurs)
                (nbre_de_joueurs, joueur0) = info_joueurs
                if nbre_de_joueurs == 2:
                    cle = str(code_cree)
                    # games[cle] = {"0": joueur0}
                    # test = games[cle]["0"]
                    setup = split_cards(nbre_de_joueurs)
                    (deck_joueur0, main_joueur0, deck_joueur1, main_joueur1, talon) = setup
                    joueur0['deck_joueur'] = deck_joueur0
                    joueur0['main_joueur'] = main_joueur0
                    print(joueur0)
                    joueur1 = {'username': '', 'couleur': ''}
                    joueur1['deck_joueur'] = deck_joueur1
                    joueur1['main_joueur'] = main_joueur0
                    joueur0['defausse0'] = []
                    joueur0['defausse1'] = []
                    joueur0['defausse2'] = []
                    joueur0['defausse3'] = []
                    joueur1['defausse0'] = []
                    joueur1['defausse1'] = []
                    joueur1['defausse2'] = []
                    joueur1['defausse3'] = []
                    joueur0['count'] = 30
                    joueur1['count'] = 30
                    # games[cle] = {"0": joueur0}
                    # games[cle] = {"1": joueur1}
                    games[cle] = {"talon": talon}
                    games[cle]['0'] = joueur0
                    games[cle]['1'] = joueur1
                    print(games[cle])
                    couleurs_restantes = couleurs
                    couleurs_restantes.remove(joueur0['couleur'])
                    print(couleurs_restantes)
                    test = games[cle]['1']['main_joueur']
                    print(len(test))
                    to_send_to_j0 = (
                    games[cle]["talon"], games[cle]['0']['deck_joueur'], games[cle]['0']['main_joueur'],
                    games[cle]['0']['count'], games[cle]['1']['deck_joueur'][0], len(test), games[cle]['1']['count'])
                    print(to_send_to_j0)
                    depart = pickle.dumps(to_send_to_j0)
                    conn.send(depart)
            elif data == "join":
                print("in")
                ask = pickle.dumps("code?")
                conn.send(ask)
                code_recu_pickled = conn.recv(2048)
                code_recu = pickle.loads(code_recu_pickled)
                print(code_recu)
                verif = games.get(str(code_recu))
                if verif is not None:
                    print("yes")
                    reponse = pickle.dumps("Yes")
                    conn.send(reponse)
                    infos_joueur_pickled = conn.recv(2048)
                    infos_joueur = pickle.loads(infos_joueur_pickled)
                    print(infos_joueur)
                else:
                    print("No")
                    reponse = pickle.dumps("No")
                    conn.send(reponse)
                    conn.close()

        except:
            break
    print("Connexion perdu")
    # conn.close()


while True:
    conn, addr = socket_de_connexion.accept()
    print("Connecté à: ", addr)
    start_new_thread(threaded_client, (conn,))

最佳答案

如果希望它是相同的套接字,则必须在窗口之间共享相同的套接字。

在我的解决方案中,我创建了一个处理套接字的类(在这种情况下,我使用QTcpSocket),如果您想处理其中存在信息交换的逻辑,则必须实现一个Command。

import pickle
import logging

from PyQt5 import QtCore, QtGui, QtWidgets, QtNetwork

logging.basicConfig(level=logging.DEBUG)

SERVER = "192.168.100.195"
PORT = 5555


class Command:
    def process_message(self, msg):
        pass


class Client(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._socket = QtNetwork.QTcpSocket(self)
        self.socket.connected.connect(self._handle_connected)
        self.socket.readyRead.connect(self._handle_readyRead)
        self.socket.stateChanged.connect(self._handle_state_changed)

        self._command = None

    @property
    def command(self):
        return self._command

    @command.setter
    def command(self, command):
        self._command = command

    def connectTo(self, host, port):
        self.socket.connectToHost(host, port)

    def disconnect(self):
        self.socket.disconnectFromHost()

    @property
    def socket(self):
        return self._socket

    @QtCore.pyqtSlot()
    def _handle_connected(self):
        logging.debug("Connected")

    @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketState)
    def _handle_state_changed(self, state):
        logging.debug("state: %s" % state)

    @QtCore.pyqtSlot()
    def _handle_readyRead(self):
        msg = self.read_data()
        logging.debug("receive message: %s" % msg)
        if isinstance(self.command, Command):
            answer = self.command.process_message(msg)
            if isinstance(answer, str):
                self.send_data(answer)

    def encode_message(self, message):
        return pickle.dumps(message)

    def decode_message(self, message):
        return pickle.loads(message)

    def send_data(self, text):
        logging.debug("send message: %s" % text)
        data = self.encode_message(text)
        self.socket.write(data)

    def read_data(self):
        data = self.socket.readAll()
        msg = self.decode_message(data)
        return msg


class CodeCommand(QtCore.QObject, Command):
    received = QtCore.pyqtSignal(bool)

    def __init__(self, code="", parent=None):
        super().__init__(parent)

        self._code = code

    @property
    def code(self):
        return self._code

    def process_message(self, msg):
        if msg == "Connecté!":
            return "join"
        elif msg == "code?":
            return self.code
            self.send_data(self.code)
        elif msg == "No":
            self.received.emit(False)
        elif msg == "Yes":
            self.received.emit(True)


class VerificationDialog(QtWidgets.QDialog):
    def __init__(self, client, parent=None):
        super().__init__(parent)
        self._client = client

        self.code_le = QtWidgets.QLineEdit(placeholderText=self.tr("Code"))
        code_validator = QtGui.QRegExpValidator(QtCore.QRegExp(r"^[0-9]{4}"))
        self.code_le.setValidator(code_validator)

        confirm_btn = QtWidgets.QPushButton(self.tr("Confirm"))
        cancel_btn = QtWidgets.QPushButton(self.tr("Cancel"))

        gridlayout = QtWidgets.QGridLayout(self)
        gridlayout.addWidget(
            QtWidgets.QLabel(self.tr("Invitation Code:")),
            0,
            0,
            alignment=QtCore.Qt.AlignRight,
        )
        gridlayout.addWidget(self.code_le, 0, 1, alignment=QtCore.Qt.AlignLeft)
        gridlayout.addWidget(confirm_btn, 1, 0, alignment=QtCore.Qt.AlignRight)
        gridlayout.addWidget(cancel_btn, 1, 1, alignment=QtCore.Qt.AlignLeft)

        gridlayout.setColumnStretch(0, 1)
        gridlayout.setColumnStretch(1, 1)

        self.code_le.setFixedSize(100, 25)
        confirm_btn.setFixedSize(100, 40)
        cancel_btn.setFixedSize(100, 40)
        size = self.sizeHint()
        self.setFixedSize(size)

        confirm_btn.clicked.connect(self.confirm)
        cancel_btn.clicked.connect(self.cancel)

    @QtCore.pyqtSlot()
    def confirm(self):
        code = self.code_le.text()
        command = CodeCommand(code)
        command.received.connect(self.on_received)
        self.client.command = command
        self.client.connectTo(SERVER, PORT)

    @QtCore.pyqtSlot()
    def cancel(self):
        self.client.disconnect()
        self.reject()

    @QtCore.pyqtSlot(bool)
    def on_received(self, state):
        if state:
            self.accept()
        else:
            messagebox = QtWidgets.QMessageBox()
            messagebox.setIcon(QtWidgets.QMessageBox.Critical)
            messagebox.setText("Fault! The code is invalid!")
            messagebox.setInformativeText(
                "Please check the validity of the code. The program will now exit."
            )
            messagebox.setWindowTitle("Oops!")
            messagebox.setStandardButtons(QtWidgets.QMessageBox.Ok)
            messagebox.exec_()
            QtCore.QCoreApplication.quit()

    @property
    def client(self):
        return self._client


class TestDialog(QtWidgets.QDialog):
    def __init__(self, client, parent=None):
        super().__init__(parent)
        self._client = client

        self.username_le = QtWidgets.QLineEdit()
        self.color_cmb = QtWidgets.QComboBox()
        self.color_cmb.addItems(["Couleur 1", "Couleur 2", "Couleur 3"])

        confirm_btn = QtWidgets.QPushButton(self.tr("Confirm"))
        cancel_btn = QtWidgets.QPushButton(self.tr("Cancel"))

        gridlayout = QtWidgets.QGridLayout(self)
        gridlayout.addWidget(
            QtWidgets.QLabel(self.tr("Username to display during the game:")), 0, 0
        )
        gridlayout.addWidget(self.username_le, 0, 1)
        gridlayout.addWidget(QtWidgets.QLabel(self.tr("Please choose a color:")), 1, 0)
        gridlayout.addWidget(self.color_cmb, 1, 1)

        lay = QtWidgets.QHBoxLayout()
        lay.addStretch()
        lay.addWidget(confirm_btn)
        lay.addWidget(cancel_btn)

        gridlayout.addLayout(lay, 3, 0, 1, 2)
        gridlayout.setRowStretch(2, 1)

        self.resize(640, 325)

        cancel_btn.clicked.connect(self.reject)
        confirm_btn.clicked.connect(self.confirm)

    @QtCore.pyqtSlot()
    def confirm(self):
        self.client.send_data("test")
        self.accept()

    @property
    def client(self):
        return self._client


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._client = Client()

        commands_menu = self.menuBar().addMenu("Commands")

        verification_action = commands_menu.addAction("Verification")
        test_action = commands_menu.addAction("Test")

        verification_action.triggered.connect(self.verification)
        test_action.triggered.connect(self.test)

    @property
    def client(self):
        return self._client

    @QtCore.pyqtSlot()
    def verification(self):
        d = VerificationDialog(self.client)
        d.exec_()

    @QtCore.pyqtSlot()
    def test(self):
        self.client.command = None
        d = TestDialog(self.client)
        d.exec_()


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

关于python-3.x - 在客户端应用程序上将一个套接字与多个窗口一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62332412/

相关文章:

python-3.x - 如何在 Sanic 中获取推荐网站 url

python-3.x - 反转字符串,但不反转整数

python - 如何使用 token 将python包发布到诗歌中的内部 Artifactory

c - 套接字读/写错误

python - MainWindow 不会同时处理事件和用户操作

python - 应用程序未在 macOS Big Sur 11.0.1 上弹出

python - 时间测量精度

java - 改进从客户端获取服务器 IP 地址的方式

c - UDP 服务器,如何做到每个线程都能收到正确的客户端数据包而不是其他线程?

python - 导入错误 : dlopen(/Users/Desktop/myapp/target/myapp_mac/cv2/cv2. cpython-36m-darwin.so, 2)