2

I made a chat application just for fun using just the socket library and threading, but now I am trying to make a GUI version of it. I am trying to have a first window where you choose your name and a second window where you send messages etc. My name window works with receiving messages but my text window does not work with receiving messages and I get:

[WinError 10022] An invalid argument was supplied. 

MY CODE: https://github.com/BenTensMexicans/pyqt5thing

EDIT: Here is my minimal example,

#SIMPLE SERVER
import socket
import threading

connections = []


def handler(conn, addr):
    while True:
        try:
            msg = conn.recv(1024).decode("utf-8")
        except:
            break
        for x in connections:
            x.send(f"{addr[0]}: {msg}".encode("utf-8"))


def start():
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   s.bind((socket.gethostbyname(), 8888))

   s.listen(5)

   while True:
       conn, addr = s.accept()
       t = threading.Thread(target=handler, args=(conn, addr))
       t.start()


start()


#PYQT5 BASIC CLIENT
import socket

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThreadPool, QThread

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        #removed setup so it does not look overwelming

        self.c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.c.connect((socket.gethostname(), 8888))

        self.lineEdit.returnPressed.connect(self.sendmsg)



        self.thread = QThread()
        self.thread.start(self.recieve())

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

    def sendmsg(self):
        self.c.send(self.lineEdit.text().encode("utf-8"))
        self.lineEdit.clear()
    def recieve(self):
        while True:
            msg = self.c.recv(1024).decode("utf-8")
            if msg:
                txt = txt + msg + "\n"
                self.plainTextEdit.setPlainText(txt)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

It does not even start but when windows prompts to terminate this and I terminate it it gives me the error previously described.

ben10mexican
  • 51
  • 1
  • 5

1 Answers1

2

Your code has several errors with the handling of threads:

  • self.thread.start(self.recieve()) doesn't make sense, it looks like you're confusing QThread with python threading.

  • Even if the above worked it would still be an error since you should not update the GUI from another thread.

Instead of messing with threads you can use QTcpSocket from QtNetwork:

import socket

from PyQt5 import QtCore, QtGui, QtWidgets, QtNetwork


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

        self._socket = QtNetwork.QTcpSocket(self)

        self.lineEdit = QtWidgets.QLineEdit()
        self.plainTextEdit = QtWidgets.QPlainTextEdit(readOnly=True)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.addWidget(self.lineEdit)
        lay.addWidget(self.plainTextEdit)

        self.socket.readyRead.connect(self.receive_message)
        self.lineEdit.returnPressed.connect(self.send_message)
        self.socket.connected.connect(self.on_connected)
        self.socket.disconnected.connect(self.on_disconnected)

        try:
            server_name = socket.gethostbyname()
        except:
            server_name = socket.gethostbyname(socket.gethostname())
        self.socket.connectToHost(QtNetwork.QHostAddress(server_name), 8888)

        self.lineEdit.setEnabled(False)

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

    def send_message(self):
        msg = self.lineEdit.text()
        self.socket.write(msg.encode("utf-8"))

    def receive_message(self):
        data = self.socket.readAll()
        msg = data.data().decode("utf-8")
        self.plainTextEdit.appendPlainText(msg)

    def on_connected(self):
        self.lineEdit.setEnabled(True)

    def on_disconnected(self):
        self.lineEdit.setEnabled(False)


if __name__ == "__main__":
    import sys

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

Note: for x in connections: it will not do anything since connections is empty, if you want there to be echo then you must add connections.append(conn) after conn, addr = s.accept()

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I forgot to add that in my example but I do have that in my real code. Thanks so much! – ben10mexican Jun 12 '20 at 03:07
  • @ben10mexican mmm, I think the error is another. You will see that the code generated by Qt Designer is not a widget but a class that fills in a widget, I recommend reading the official docs: https://www.riverbankcomputing.com/static/Docs/PyQt5/designer.html#using-the-generated-code and also my answer: https://stackoverflow.com/questions/46544780/qtdesigner-changes-will-be-lost-after-redesign-user-interface – eyllanesc Jun 15 '20 at 22:27