pythonpyqtpyqt5qtcpsocketqtcpserver

PyQt5: Sending and receiving messages between client and server


I am trying to create a server and client to send and receive messages. My problem is to send and receive between the client and the server.

client.py:

from PyQt5.QtCore import QIODevice
from PyQt5.QtWidgets import QApplication, QDialog
from PyQt5.QtNetwork import QTcpSocket

class Client(QDialog):
    def __init__(self):
        super().__init__()
        HOST = '127.0.0.1'
        PORT = 8000
        self.tcpSocket = QTcpSocket(self)
        self.tcpSocket.connectToHost(HOST, PORT, QIODevice.ReadWrite)
        self.tcpSocket.readyRead.connect(self.dealCommunication)
        self.tcpSocket.error.connect(self.displayError)

    def dealCommunication(self):
        print("connected !\n")
        # i want here to send and receive messages

    def displayError(self):
        print(self, "The following error occurred: %s." % self.tcpSocket.errorString())

if __name__ == '__main__':

    import sys
    app = QApplication(sys.argv)
    client = Client()
    sys.exit(client.exec_())

server.py:

import sys
from PyQt5.QtCore import QByteArray, QDataStream, QIODevice
from PyQt5.QtWidgets import QApplication, QDialog
from PyQt5.QtNetwork import QHostAddress, QTcpServer, QTcpSocket

class Server(QDialog, QTcpSocket):
    def __init__(self):
        super().__init__()
        self.tcpServer = None

    def sessionOpened(self):
        self.tcpServer = QTcpServer(self)
        PORT = 8000
        address = QHostAddress('127.0.0.1')
        self.tcpServer.listen(address, PORT)
        self.tcpServer.newConnection.connect(self.dealCommunication)

    def dealCommunication(self):
        # i want here to send and receive messages 
        data = input()
        block = QByteArray()
        out = QDataStream(block, QIODevice.ReadWrite)
        out.writeQString(data)
        clientConnection = self.tcpServer.nextPendingConnection()
        clientConnection.write(block)
        clientConnection.disconnectFromHost()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    server = Server()
    server.sessionOpened()
    sys.exit(server.exec_())

I have searched but I am so confused. I found some code, but I can't understand what it does exactly:

data = input()
block = QByteArray()
out = QDataStream(block, QIODevice.ReadWrite)
out.writeQString(data)
clientConnection = self.tcpServer.nextPendingConnection()
clientConnection.write(block)
clientConnection.disconnectFromHost()

Solution

  • client.py

    from PyQt5.QtCore import QDataStream, QIODevice
    from PyQt5.QtWidgets import QApplication, QDialog
    from PyQt5.QtNetwork import QTcpSocket, QAbstractSocket
    
    class Client(QDialog):
        def __init__(self):
            super().__init__()
            self.tcpSocket = QTcpSocket(self)
            self.blockSize = 0
            self.makeRequest()
            self.tcpSocket.waitForConnected(1000)
            # send any message you like it could come from a widget text.
            self.tcpSocket.write(b'hello')
            self.tcpSocket.readyRead.connect(self.dealCommunication)
            self.tcpSocket.error.connect(self.displayError)
    
        def makeRequest(self):
            HOST = '127.0.0.1'
            PORT = 8000
            self.tcpSocket.connectToHost(HOST, PORT, QIODevice.ReadWrite)
    
        def dealCommunication(self):
            instr = QDataStream(self.tcpSocket)
            instr.setVersion(QDataStream.Qt_5_0)
            if self.blockSize == 0:
                if self.tcpSocket.bytesAvailable() < 2:
                    return
                self.blockSize = instr.readUInt16()
            if self.tcpSocket.bytesAvailable() < self.blockSize:
                return
            # Print response to terminal, we could use it anywhere else we wanted.
            print(str(instr.readString(), encoding='ascii'))
    
        def displayError(self, socketError):
            if socketError == QAbstractSocket.RemoteHostClosedError:
                pass
            else:
                print(self, "The following error occurred: %s." % self.tcpSocket.errorString())
    
    
    if __name__ == '__main__':
        import sys
    
        app = QApplication(sys.argv)
        client = Client()
        sys.exit(client.exec_())
    

    server.py

    import sys
    from PyQt5.QtCore import QByteArray, QDataStream, QIODevice
    from PyQt5.QtWidgets import QApplication, QDialog
    from PyQt5.QtNetwork import QHostAddress, QTcpServer
    
    class Server(QDialog):
        def __init__(self):
            super().__init__()
            self.tcpServer = None
    
        def sessionOpened(self):
            self.tcpServer = QTcpServer(self)
            PORT = 8000
            address = QHostAddress('127.0.0.1')
            if not self.tcpServer.listen(address, PORT):
                print("cant listen!")
                self.close()
                return
            self.tcpServer.newConnection.connect(self.dealCommunication)
    
        def dealCommunication(self):
            # Get a QTcpSocket from the QTcpServer
            clientConnection = self.tcpServer.nextPendingConnection()
            # instantiate a QByteArray
            block = QByteArray()
            # QDataStream class provides serialization of binary data to a QIODevice
            out = QDataStream(block, QIODevice.ReadWrite)
            # We are using PyQt5 so set the QDataStream version accordingly.
            out.setVersion(QDataStream.Qt_5_0)
            out.writeUInt16(0)
            # this is the message we will send it could come from a widget.
            message = "Goodbye!"
            # get a byte array of the message encoded appropriately.
            message = bytes(message, encoding='ascii')
            # now use the QDataStream and write the byte array to it.
            out.writeString(message)
            out.device().seek(0)
            out.writeUInt16(block.size() - 2)
            # wait until the connection is ready to read
            clientConnection.waitForReadyRead()
            # read incomming data
            instr = clientConnection.readAll()
            # in this case we print to the terminal could update text of a widget if we wanted.
            print(str(instr, encoding='ascii'))
            # get the connection ready for clean up
            clientConnection.disconnected.connect(clientConnection.deleteLater)
            # now send the QByteArray.
            clientConnection.write(block)
            # now disconnect connection.
            clientConnection.disconnectFromHost()
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        server = Server()
        server.sessionOpened()
        sys.exit(server.exec_())
    

    It comes with very limited error handling but shows you the basics.

    Edited to explain the code you wanted explaining