Wie sicher ist os.pipe() zum Triggern in der tk Task?

Fragen zu Tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@sparrow Ja, da hast Du wohl recht. Aber trotzdem werd ich nicht jetzt noch damit anfangen statt UDP TCP zu implementieren. Da wäre noch etwas zusätzlicher Aufwand nötig, weil sich der Router dann auch noch die Connections merken muss. Viel wäre ja nicht zu tun. Aber genaugenommen, brauche ich das ja alles nicht. Wollte nur sehen, zu was mein Proxy taugt.

Ein zsätzliches boolsches Flag bei der Definition eines Callbacks erlaubte, dass ein Callback nicht nur die Message erhielt, sondern auch bei Bedarf die Message ID. Damit war dann Routing in andere Threads möglich.
Dass man nicht nur einen boolschen Wert nehmen kann, sondern auch etwas Beliebiges, erlaubt, dass der Callback zusätzlich noch einen weiteren Parameter bekommt. Das kann das alles Mögliche sein, etwa eine Port Adresse oder eine IP Adresse. Damit ist dann Routing über Netzwerke möglich.

Ich denke für Routing zwischen Anwendungen auf dem eigenen PC über localhost sollte wohl UDP reichen. Da sollte normalerweise kein Bit umkippen und somit kein Paket unbrauchbar werden. Wenn man vor hat, über ein Netzwerk zu gehen, sollte man TCP verwenden.

Und ob man dann dafür etwas Eigenes verwenden sollte, bin ich skeptisch. Lieber in so einem Fall wohl dann etwas Erprobtes und Bewährtes nehmen und das dann noch mit anbinden, entweder an die Applikation über ein modifiziertes Sende und Empfangsteil oder als eigenständige Anwendung entweder als modifizierter Router oder über den UDP Router - im Falle mehrer miteinander kommunizierender Anwendungen.

Aber damit sind wir jetzt ganz vom Thema abgekommen. Naja, os.pipe sollte wohl sicher sein als Trigger für Message Austausch der tk Anwendung mit anderen Threads. Ob man den Aufwand betreiben will ein paar Zeilen mehr Code zu schreiben, oder einfach mit after pollt das kann man sich aussuchen.

Und auch damit bin ich von meinem eigenen Anliegen abgekommen, nämlich dem GUI Designer. Und dafür brauche ich den Message Austausch zwischen verschiedenen Threads auch nicht. Habe nur meinen Proxy für threadinterne Messages geringfügig erweitert, so dass er auch für Messageaustausch überall hin auch über über Netzwerke taugt - und habe es mal ausprobiert.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Alfons Mittelmeyer hat geschrieben:Ich denke für Routing zwischen Anwendungen auf dem eigenen PC über localhost sollte wohl UDP reichen. Da sollte normalerweise kein Bit umkippen und somit kein Paket unbrauchbar werden. Wenn man vor hat, über ein Netzwerk zu gehen, sollte man TCP verwenden.
Eine Verbindung über `localhost` stellt genau so ein Netzwerk dar. Nur eben eines auf engstem Raum.

Deine Folgerung, die sich für mich so liest, als solle man für geringe Übertragungswege bevorzugt UDP verwenden, weil da ja angeblich nicht viel schief gehen kann, halte ich für sehr gewagt. Man möchte IMHO grundsätzlich TCP verwenden und UDP nur dann nutzen, wenn gute Gründe gegen TCP sprechen. Und nein: Die Tatsache, dass du anscheinend nicht weißt, wie man Polling (oder ähnliche Techniken) mit einem TCP-Client betreibt, ist für mich definitiv kein sinnvoller Grund, stattdessen auf UDP zu setzen.

Aber: Es ist dein Programm (oder Theorie). Mach, was du willst. Machste ja eh. :)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Übrigens wird hier mit viel Beispielcode unter anderem beschrieben, wie man die plattformübergreifende `select()`-Funktion aus dem gleichnamigen Modul der Standardbibliothek nutzen kann. Man muss schon ein wenig Aufwand betreiben, aber hat dafür am Ende eine robuste Implementierung, wenn man alles richtig gemacht hat.

Bei Interesse einfach mal im Netz schauen, ob diesbezüglich vielleicht schon jemand etwas vorgefertigtes als Bibliothek bereitstellt, sodass man nicht soviel eigenen Code dafür schreiben muss.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@snafu Hab es eh schon mit TCP gemacht und sicherer, schneller und cleverer als in solchen Beispielen. select geht ewa unter Unix, aber ist nicht für Windows.
Ich benutze einen Router mit ThreadingMixIn und die Clients des Routers haben auch einen Server. Hier der Server meines Routers:

Code: Alles auswählen

HOST, PORT = "localhost", 9999

class MyTCPHandler(socketserver.StreamRequestHandler):

    def handle(self):
        # messages, which requires its socket as parameter ================
        commands = {ECHO:False,ID_REQUEST:True,REGISTER:True,DISCONNECT:True}

        # client connects and sends its ip and port address of its server ================
        message = str(self.rfile.readline().strip(), "utf-8")
        json_message = json.loads(message)
        receiver_address=(json_message[0],json_message[1])

        # connect to clients server and send an info ================
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect(receiver_address)
        worker.proxy.send_extern_highprio(INFO,(sock,"Router Connected with: " + str(receiver_address)))

        # further messages of the client =====================
        while True:       

            message = self.rfile.readline()
            if len(message) == 0: break
            
            message_id = message[0:4] # first 4 bytes are the message id

            # for router command messages we need the socket as a parameter for responding to the client or to register or unregister message ids for the client
            if message_id in commands:
                if commands[message_id]: worker.proxy.send_extern_highprio(message_id,(sock,message))
                else: worker.proxy.send_extern(message_id,(sock,message))

            # socket parameter not required: registered messages are sent to the clients, which did register for message ids
            else: worker.proxy.send_extern(message_id,message)
            
        # if the client ends the session, we unregister all its message ids and close the socket
        worker.proxy.send_extern_highprio(DISCONNECT,(sock,None))
        print("Router Connection closed:",receiver_address) 
       
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    allow_reuse_address = True

server = ThreadedTCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Wenn ein Client sich verbindet, sendet er zuerst die IP und Port Adresse seines Servers. Daraufhin wird eine Socket Verbindung mit seinem Server eröffnet.
Die Kommunikation erfolgt dann ohne Warten auf Response und daher schnell.
BlackJack

@Alfons Mittelmeyer: `select()` funktioniert auch bei Windows für Sockets.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Ach so, für sockets gehts schon, aber brauche ich nicht.

Wenn eine Message beim Server des Routers eintrifft, übergibt dieser sie dem worker:

Code: Alles auswählen

            # socket parameter not required: registered messages are sent to the clients, which did register for message ids
            else: worker.proxy.send_extern(message_id,message)
Und der worker routet sie an alle registrierten Clients:

Code: Alles auswählen

    def route(self,message_with_sock_dictionary): # normal routing
        sock_dictionary = message_with_sock_dictionary[0]
        message = message_with_sock_dictionary[1][1]
        for sock in sock_dictionary: sock.sendall(message)
Ist doch optimal, oder?
Zuletzt geändert von Alfons Mittelmeyer am Sonntag 13. September 2015, 21:01, insgesamt 1-mal geändert.
BlackJack

@Alfons Mittelmeyer: Nein.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Anderer Meinung, wieso?
Antworten