Reputation: 225
Quick question here... (By the way, sorry if it has been already answered...) I have a QDialog window (created by a QMainWindow) where I created and used a socket. After some manipulations, the QDialog window closes (by using the QDialog.accept()
command) then a new different QDialog window is opened (by the QMainWindow). From that new window, I want to be able to send infos to the server with the already opened socket.
I tried to do that by using these lines of code:
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
Then, when I tried to send something I get the following error:
OSError: [ErrnOSError: [Errno 57] Socket is not connected
But the server is showing me in the console that the socket created in the previous QDialog is still opened (I didn't closed it on purpose, because I want to continue to use it through the multiple windows of my program.)
Is there a way to reuse that already opened socket trough multiple window?
By the way, each window in my program has there code in separate file.
EDIT:
Here is some more infos to help out:
Code for my first 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_()
And here is my second QDialog in a different file:
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_()
Here is the code on the server side:
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,))
Upvotes: 1
Views: 266
Reputation: 244132
If you want it to be the same socket then you must share the same socket between the windows.
In my solution I have created a class that handles the socket (in this case I use a QTcpSocket), and if you want to handle a logic in which there is information exchange then you must implement a 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()
Upvotes: 2