@BlackJack Das mit UDP war ja nur mal zum Ausprobieren und sollte auf dem eigenen PC über localhost wohl auch sicher sein. Und für Anderes würde man dann etwas Bewährtes nehme. Da bräuchte man ja nur das Empfangsteil austauschen und ein paar Zeilen im Sendeteil. Hier dieses Sende und Empfangsteil:
Code: Alles auswählen
import socket
import socketserver
import threading
import json
import extern_proxy
import proxy as myproxy
HOST, PORT = "localhost", 8888
MYPORT = 0
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Sender gets port for receiver ==================================
sock.sendto(bytes("PORT?", "utf-8"), (HOST, PORT))
MYPORT = int.from_bytes(sock.recv(16), byteorder='big')
# RECEIVER ===== receives from router =========================
class MyUDPHandler(socketserver.BaseRequestHandler):
def handle(self):
message = json.loads(str(self.request[0], "utf-8"))
extern_proxy.proxy.receive_extern(message)
socket = self.request[1]
socket.sendto(bytes('OK', "utf-8"), self.client_address)
class ServerThread(threading.Thread):
def run(self):
print("Receiver",HOST,MYPORT)
server = socketserver.UDPServer((HOST, MYPORT), MyUDPHandler)
server.serve_forever()
receiverthread=ServerThread()
receiverthread.daemon = True
receiverthread.start()
# SENDER ===== sends to router - own thread, because shouldn't block tranmissions between threads ==
proxy = None
class MyThread(threading.Thread):
def send_to_router(self,message):
data=json.dumps(message)
sock.sendto(bytes(data, "utf-8"), (HOST, PORT))
sock.recv(16)
def do_send_to_router(self,message_ids):
proxy.do_receive_extern(message_ids)
for mid in message_ids: proxy.do_receive(None,mid,self.send_to_router,True)
def do_receive_from_router(self,message_ids):
message = ("ROUTE",(MYPORT,message_ids))
self.send_to_router(message)
def run(self):
global proxy
self.proxy = myproxy.Proxy(extern_proxy.proxy)
proxy = self.proxy
self.proxy.loop()
mythread = MyThread()
mythread.daemon = True
mythread.start()
def do_send_to_router(message_ids):
proxy.send_extern_highprio("execute_function",lambda: mythread.do_send_to_router(message_ids))
def do_receive_from_router(message_ids):
proxy.send_extern_highprio("execute_function",lambda: mythread.do_receive_from_router(message_ids))
Auszutauschen wäre das, nämlich dass man eine Port und/oder IP Adresse erhält - im Falle eines eigenen Routers.
Wenn man etwas anderes nimmt, geschieht das wohl von selbst. Nur man braucht diese Identifikation, damit der Router die Messages für diese Anwendung dieser Anwendung schicken kann.
Code: Alles auswählen
# Sender gets port for receiver ==================================
sock.sendto(bytes("PORT?", "utf-8"), (HOST, PORT))
MYPORT = int.from_bytes(sock.recv(16), byteorder='big')
Auszutauschen wäre der Empfang. Wichtig ist nur der Ersatz für:
Code: Alles auswählen
message = json.loads(str(self.request[0], "utf-8"))
extern_proxy.proxy.receive_extern(message)
Und auszutauschen im Sendeteil wäre:
Code: Alles auswählen
sock.sendto(bytes(data, "utf-8"), (HOST, PORT))
sock.recv(16)
Erläuterungen:
do_send_to_router erhält eine Liste der Message IDs die zum Router gehen sollen. Diese Message IDs werden eingetragen bei der Zentralen Routing Task für Messageaustausch zwischen Treads, damit diese diese Messages der Queue des Sendeteils übergibt: proxy.do_receive_extern(message_ids)
Dann werden diese Message IDs im Sendeteil eingetragen, damit diese Messages an den Router geschickt werden: for mid in message_ids: proxy.do_receive(None,mid,self.send_to_router,True)
do_receive_from_router sendet an den Router eine Message mit der ID "ROUTE", die Port Adresse des Empfangsteil und eine Liste der Message IDs, die der Router an das Empfangsteil senden soll.
Das Empfangsteil übergibt empfangene Messages der Queue der zentralen Message Routing Task (zwischen Threads) - extern_proxy.proxy
Vielleicht sollte ich bei do_send_to_router noch einen zusätzlichen Parameter machen - den owner (self des Threads) - jetzt auf None gesetzt, für den Fall, dass man einen Thread beendet. Dann kann dieser Thread die im zugeordneten Messages zum Router wieder austragen.
do_receive_from_router gilt allerdings applikationsweit, da der Router nur den Port der Anwendung hat und keine Referenz auf einen Thread. Aber da kann auch nichts passieren. Wenn man diese Messages nicht austrägt, werden sie sowieso intern nicht weiter geleitet.
Implementieren muss ich noch eine Funktion, nämlich die Abmeldung der Applikation beim Router mittels "UNROUTE". Das sollte bei einer GUI Anwendung nach der mainloop geschehen und sollte auf Rückmeldung warten. Also eine Pollschleife für die Rückmeldung. Die Frage ist allerdings, was bei gewaltsamem Abbruch geschieht, etwa Stoppen des Prozesses.
Naja, dann kann der Router eben nicht mehr an diese Port Adresse senden - und könnte in diesem Falle selbst die Message IDs austragen, falls diese noch von einer anderen Anwendung gesendet werden.
Also try für senden und timeout für warten auf Bestätigung und bei den eingetragenen Messages muss man auch den Owner mit berücksichtigen, sonst löscht man diese Messages für alle - zur Zeit werden nur die Callbacks berücksichtigt. Das ist noch ein Fehler - für das externe Routing.
Also beim Router ist das falsch: self.proxy.do_receive(None,"UNROUTE",self.proxy.undo_receiveAll)
Und Messages zum Router müssen auch pro Owner eingetragen werden aber nur einmal aufgerufen werden - damit ein sich abmeldender Thread nicht diese Message auch für andere Thread abmeldet. Aber man kann sie auch drin lassen, stört ja nicht - ist wohl das Einfachste.
Die Lösung wäre statt Callback auch ein Tuple aus Callback und Owner zulassen.
Nein, jetzt habe ich es: Ownersdictionary pro Callback mit Referenzzähler auf die Owner bzw. Dictionary empty
Das heißt, dass dann der optionale Parameter auch ein Tuple sein kann, welches zusätzlich ein Owners Dictionary hat.
Das kann ich dann auch mal testen. Zur Zeit kommt ein und dieselbe Message wohl nur bei einer Applikation an, weil die Applikationen die MessageID beim Router überschreiben
Ja, ist so!
Also, mir geht es nicht um TCP, UDP oder sonst etwas, sondern um die Signal Framework Logik.