einer abgeleiteten Klasse in einem Thread eine Queue mitgeben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

Hallo Leute,
ich scheitere an dem Punkt, dem Server-thread meine Queue q mitzugeben. Problem in Zeile 34.
die __init__ gehört zum Originalbeispiel nicht dazu, die habe ich reingebastelt, ich vermute aber so in dieses Richtung müsste man das machen?
Wie gesagt, ich finde einfach keinen Weg die Queue beim erstellen mitzugeben.
mein Ziel: Ich möchte eigentlich nur die empfangenen Daten des UDP-Server (data) aus der Klasse 'MyUdpHandler' an die Klasse 'mainWindow' weiterreichen.
Aber ich finde nicht raus wie ich diese Queue hier reinbauen muss. Was hab ich hier nur wieder nicht richtig gemacht?

Code: Alles auswählen

#socketserverUDP von docs.python.org
from socketserver import BaseRequestHandler, UDPServer
from threading import Thread
from queue import Queue, Empty
from tkinter import Tk, Label

class MyUdpHandler(BaseRequestHandler):

    def __init__(self, request, client_address, server, myQueue):
        BaseRequestHandler.__init__(self, request, client_address, server)
        self.q = myQueue
        pass

    def handle(self):
        self.data = self.request[0].strip()
##        socket = self.request[1]
        print("[{}] - {} - {}".format(self.client_address[0], self.client_address[1], self.data.decode()))

class mainWindow(Tk):
    def __init__(self, q):
        self.q = q
        Tk.__init__(self)
        self.labelData = Label(self, text='-----')
        self.labelData.pack()
        self.mainloop()

if __name__ == "__main__":

    q = Queue()

## Serverstart als eigener Thread ------------------------------------
    HOST, PORT = "", 51456
    server = UDPServer((HOST, PORT), MyUdpHandler)
    serverThread = Thread(target=server.serve_forever, myQueue=(q))
    serverThread.start()
## Ende Serverstart
    
## Starte Fenster ----------------------------------------------------
    mainWindowThread = Thread(target=mainWindow, args=(q,)).start()
## Ende Start Fenster
die fehlermeldung beim Programmstart:
Traceback (most recent call last):
File "C:/socketserver_01g_QueueQueue.py", line 34, in <module>
serverThread = Thread(target=server.serve_forever, myQueue=(q))
TypeError: __init__() got an unexpected keyword argument 'myQueue'

Process finished with exit code 1


Vielen Dank
BlackJack

@XCDRiVER: Erst mal: Die GUI würde ich nicht in einem eigenen Thread starten. Die würde ich immer im Hauptthread lassen. Beim gezeigten Programm macht es ja auch gar keinen Sinn am Ende *drei* Threads zu haben und Du würdest nach dem Start dann ja sowieso gleich wieder ein `join()` machen. Dem `MyUdpHandler` (schlechter Name) kannst Du nichts in der `__init__()` mitgeben. Die Exemplare erstellst Du doch auch gar nicht, sondern der Server. Der gibt dem Handler aber sich selbst mit und in der `handle`-Methode ist das Server-Objekt auch verfügbar über `self.server`. Das heisst Du kannst im Server die `__init__()` implementieren und dort zusätzliche Argumente übergeben und Sachen an das Objekt binden.
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

Hallo BlackJack,
vielen Dank für die Informationen.
wenn du von der Server-init schreibst der ich was mitgeben kann, meinst du direkt die init vom 'UDPServer()' in der socketserver.py?
Dort ist der richtige Platz um meine Queue 'anzumelden'?
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

der betreffende Konstruktor für den Server wäre dann der TCPServer Konstruktor aus der socketserver.py
UDPServer selbst hat keinen Konstruktor, nur ein paar Funktionen und leitet vom TCPServer ab.
kann ich diesen TCPServer Konstruktor aus meinem Programm heraus erweitern?
Ich würde wirklich sehr ungerne in den Bibliotheken herum schreiben.

PS: Ja es geht wohl, ich denke ich habe es
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@XCDRiVER: Klassen erweitert man, indem man sie vererbt, genauso wie UDPServer die Funktionalität von TCPServer erbt, so mußt Du halt eine eigene Klasse mit einer __init__ schreiben, die von UDPServer erbt. Deine mainWindow-Klasse ist übrigens seltsam. Eine __init__-Methode sollte nicht endlos laufen.
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

@Sirius3,
vielen dank, das mit der GUI hat BlackJack auch gesagt, da kümmere ich mich auch drum.
ich denke die Queue habe ich jetzt am laufen, ich habe mir, wie ihr beschrieben habt, eine eigene UDPServer-Klasse abgeleitet.
Ich bastele mal noch ein wenig und melde mich bei Problemen wieder,
übrigens:
das ist eine Spitzen-Reaktionszeit hier im Python-Forum.
und dazu beeindruckend kompetent. Vielen Dank
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

Hallo Forum,
ich habe hier im Code folgendes Problem,
die Informationen, die als 'self.data' in der Klasse MyUdpHandler anstehen, müssten (irgendwie artgerecht) zur Klasse myUDPServer transportiert werden, damit ich die mit der Queue q an meine GUI weiterreichen kann.
So denke ich mir das zumindest.
Ich bräuchte mal einen Schubs wie ich da am besten weiter vorgehen sollte.
(Zeile 9 ist nur zum Test da ob die Queue auch funktioniert)
Vielen Dank.

Code: Alles auswählen

from queue import Queue, Empty
from tkinter import Tk, Frame, Label

class myUDPServer(UDPServer):

    def __init__(self, server_address, RequestHandlerClass, q, bind_and_activate=True):
        UDPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate=True)
        self.q = q
        self.daten = self.server_address
        self.q.put(self.daten)

class MyUdpHandler(BaseRequestHandler):

    def handle(self):
        self.data = self.request[0].strip()
##        socket = self.request[1]
        print("[{}] - {} - {}".format(self.client_address[0], self.client_address[1], self.data.decode()))

class mainWindow(Frame):
    def __init__(self, q, master=None):
        super(mainWindow, self).__init__(master)
        self.pack()
        self.q = q
        self.message = self.q.get(timeout=1)
        self.labelData = Label(self, text=self.message)
        self.labelData.pack()

if __name__ == "__main__":

    q = Queue()

## Serverstart als eigener Thread ------------------------------------
    HOST, PORT = "", 51456
    server = myUDPServer((HOST, PORT), MyUdpHandler, q)
    serverThread = Thread(target=server.serve_forever)
    serverThread.start()
## Ende Serverstart
    
## Starte Fenster ----------------------------------------------------
    root = Tk()
    fenster = mainWindow(q, master=root)
    fenster.mainloop()
## Ende Start Fenster
BlackJack

@XCDRiVER: Der Handler kennt ja den Server, der hat den als Attribut, also kannst Du darüber auch problemlos auf dessen `q`-Attribut zugreifen.
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

@BlackJack, ich hab ein paar Zeilen Code ausprobiert aber
ich hab keinen Schimmer wo ich was machen muss, um an die Daten vom handle() zu kommen.
self.q in den handle() zu schreiben funktioniert leider nicht. Dort ist der nicht bekannt.
Ich stehe auf dem Schlauch ...
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na dann lies mal https://docs.python.org/2/library/socke ... er-objects aufmerksam durch, insbesondere die Beschreibung der Methode "handle()".

Kleiner Tipp: faengt an mit "and the server instance as ..."
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

@__deets__ habe ich self.server so korrekt eingesetzt? Zumindest bekomme ich tatsächlich Daten aus der handle()
Vielen Dank bis hier her, ich probiere mal noch etwas und melde mich dann wieder. Dankeschöööön :)

Code: Alles auswählen

#socketserverUDP von docs.python.org
from socketserver import BaseRequestHandler, UDPServer
from threading import Thread
from queue import Queue, Empty
from tkinter import Tk, Frame, Label

class myUDPServer(UDPServer):

    def __init__(self, server_address, RequestHandlerClass, q, bind_and_activate=True):
        UDPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate=True)
        self.q = q

class MyUdpHandler(BaseRequestHandler):

    def handle(self):
        self.data = self.request[0].strip()
##        socket = self.request[1]
        self.server.q.put(self.data)
        print("[{}] - {} - {}".format(self.client_address[0], self.client_address[1], self.data.decode()))

class mainWindow(Frame):
    def __init__(self, q, master=None):
        super(mainWindow, self).__init__(master)
        self.pack()
        self.q = q
        self.message = self.q.get(timeout=1)
        self.labelData = Label(self, text=self.message)
        self.labelData.pack()

if __name__ == "__main__":

    q = Queue()

## Serverstart als eigener Thread ------------------------------------
    HOST, PORT = "", 51456
    server = myUDPServer((HOST, PORT), MyUdpHandler, q)
    serverThread = Thread(target=server.serve_forever)
    serverThread.start()
## Ende Serverstart
    
## Starte Fenster ----------------------------------------------------
    root = Tk()
    fenster = mainWindow(q, master=root)
    fenster.mainloop()
## Ende Start Fenster
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Grundsaetzlich ja, wie sinnvoll die gesamte Vorgehensweise ist, steht auf einem anderen Blatt. Ich wuerde ja in einem Timer periodisch pruefen, statt hart eine Sekunde zu warten. Wenn du das tust, brauchst du die ganze Nebenlaeufigkeit nicht & kannst deine Anfrage gleich synchron machen.
Antworten