QtNetwork.QTcpServer - Events

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

Nach längerem hin und her habe ich das Qt-Framework gefunden.
Neben der komfortablen Nutzung von UI-Elementen möchte ich auch die Netzwerkunterstützung nutzen.

Der Server inclusive des Clienthandlings laufen soweit:

Code: Alles auswählen

class Client(QtCore.QObject):
    def SetSocket(self, socket):
        self.rx_counter = 0
        self.tx_counter = 0
        self.socket = socket
        self.socket.connected.connect(self.on_connected)
        self.socket.disconnected.connect(self.on_disconnected)
        self.socket.readyRead.connect(self.on_readyRead)
        frm_main.print_memo("Client Connected from {}:{}".format(self.socket.peerAddress().toString(),
                                                                 self.socket.peerPort()))

    def on_connected(self):
        frm_main.print_memo("Client Connected Event")

    def on_disconnected(self):
        frm_main.print_memo("Client Disconnected")

    def on_readyRead(self):
        msg = self.socket.read(2)
        bytes_to_read = int.from_bytes(msg[1], "big")
        msg += self.socket.read(bytes_to_read)   
        data = bytearray(msg)
        if data[0] == 0x68:  #start
            if data[1] == len(data)-2:
                #S-Frame
                if data[2] & 0b00000011 == 0b01:    #01 S-Frame
                    self.handle_sFrame(data)
                #U-Frame
                if data[2] & 0b00000011 == 0b11:    #11 U-Frame
                    self.handle_uFrame(data)
                #I-Frame        
                if data[2] & 0b00000001 == 0b0:     #.0 I-Frame 
                    self.rx_counter += 1
                    self.handle_iFrame(data)
            else:
                frm_main.print_memo("Wrong size of incomming IEC 60870-5-104 Frame")
     
        
class Server(QtCore.QObject):
    def __init__(self, parent=None):
        QtCore.QObject.__init__(self)
        self.TCP_LISTEN_TO_PORT = 2404
        self.server = QtNetwork.QTcpServer()
        self.server.newConnection.connect(self.on_newConnection)
        self.server.serverPort = self.TCP_LISTEN_TO_PORT
        self.ip = QtNetwork.QHostAddress()
        self.ip.setAddress("127.0.0.1")

    def on_newConnection(self):
        while self.server.hasPendingConnections():
            frm_main.print_memo("Incoming Connection...")
            self.client = Client(self)
            self.client.SetSocket(self.server.nextPendingConnection())

    def StartServer(self):
        if self.server.listen(self.ip, self.TCP_LISTEN_TO_PORT):   #QtNetwork.QHostAddress.Any
            frm_main.print_memo(
                "Server is listening on {}:{}".format(self.ip.toString(),
                                                      self.TCP_LISTEN_TO_PORT))
        else:
            frm_main.print_memo("Server couldn't wake up")

Verständnisprobleme habe ich mit diesen functions:

Code: Alles auswählen

        self.socket.connected.connect(self.on_connected)
        self.socket.disconnected.connect(self.on_disconnected)
        self.socket.readyRead.connect(self.on_readyRead)
on_readyRead: läuft wie erwartet.
on_connected: diese function wird bisher gar nicht aufgerufen. Nicht so schlimm, hätte ich aber anders erwartet.
on_disconnected: wir nur aufgerufen wenn der Client endgültig geschlossen wurde.
Hier hätte ich erwartet, dass ein "durchbooten" des Clients erkannt wird.
Das hat zur Folge, dass mein Client offen bleibt und der durchgebootete Client eine neue Verbindung und damit einen weiteren Client startet.

Hat jemand Erfahrung mit dem Qt-Framework und kann mir hier einen Tipp geben?

Gruß
pf@nne
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Qt bietet - anders als die schon mehrfach erwähnten Middlewares - keinerlei Mehrwert in Bezug auf socket Programmierung. Da muss man das alles genauso vom Hand herstellen.
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

OK, schade ....
Ich hätte gedacht, dass die vorhandenen Events mir diese Funktionalitäten abnehmen würden.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Events uebersetzen nur die normalen Ereignisse in die Welt von signals und slots. Nicht mehr, nicht weniger. Die ganzen Fehlerzustaende, die man so bekommen kann, muss man dann durch Erfahrung und veraenderte Protokolle herstellen. "broken pipe" (was dann denke ich mal zu disconnected fuehrt) muss man zB durch eine keep-alive Message aktiv herbeifuehren. Etc. pp.

Oder eben etwas benutzen, welches das schon alles fuer einen gemacht hat. Aber da waren wir ja schon.
HBerger
User
Beiträge: 8
Registriert: Montag 23. August 2021, 13:29

Qt bietet - anders als die schon mehrfach erwähnten Middlewares - keinerlei Mehrwert in Bezug auf socket Programmierung
Das ist IMHO ein bisserl hart formuliert :-)
Funktional gesehen hasst sicher recht, und bei den high level Sprachen auch vielleicht syntaktisch.

Aber, Qt ist initial ein C++ Framework, und die (low level) Socket Schnittstellen sind ein da ein Graus ....
Gibt zwar auch wesentlich bessere Abstraktionen von TCP,
Aber wenn man da Qt eh schon am Hals hat (weil Qt Gui) dann ist QSocket schon auch ne Überlegung wert (wenn man nichts spezielles braucht) .... passt auch besser in die (gesamt) Landschaft.

Wenn man mehr Komfort will, sollte man eh auch über ein anderes / höheres Protokoll nachdenken ... je nach Anwendung, da gibts dann auch ganz andere Bibs dafür.
HBerger
User
Beiträge: 8
Registriert: Montag 23. August 2021, 13:29

on_disconnected: wir nur aufgerufen wenn der Client endgültig geschlossen wurde.
1. der socket bleibt offen, solange er nicht geschlossen oder zerstört wird, oder die gegenseite halt ...
zerstört wird in python nicht controlliert (garbage collection) also soltest du aktiv close aufrufen, wenn die verbindung schliessen willst.

2. Sockets haben imho kein Fehlerhandling, sprich alles funktioniert über errorcodes bei einer aktiven Aktion.
du muesstest das selber pollen, aka nen read aufrufen, entweder bringt er 0 byte gelesen oder timeout / fehler wenn die verbindung nimmer steht

oder alternativ, wie schon empfohlen, eigenes keep alive implementieren
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

OK, danke für die Antworten.
Bei dem von mit genutzten Protokoll sind Testframes ausdrücklich vorgesehen.
Die werde ich dann aktiv triggern und auswerten.
Antworten