Sirius3 hat geschrieben:@Alfons Mittelmeyer: was soll der Server überhaupt können? Da TCP schon von sich aus reliable ist, braucht man nicht alles mit einem sinnfreien Ok bestätigen. Was gesendet wird, kommt auch an, oder man bekommt ein broken Pipe. Genauso die Sache mit dem loop. Nromalerweise sendet man Befehle, bis man keine Lust mehr hat und sendet dann entweder ein QUIT o.ä. oder man schließt einfach die Verbindung, dann ist auch klar, dass da wohl keine weiteren Befehle mehr kommen.
Was der Server können soll?
Es handelt sich nicht um einen Server und Clients, sondern um einen Router und Clients des Routers. Der Router dient dazu, dass Clients Messages miteinander austauschen können, ohne sich gegenseitig zu kennen. Es geht dabei um schnellen Messageaustausch zwischen einer überschaubaren Anzahl von Clients, also nicht dass tausende von Clients nur jeweils kurzzeitig einen Request wollen, sondern eher um eine verteilte Applikation in der vielleicht nur fünf Clients schnell miteinander kommunizieren können.
Dazu soll nicht bei jeder Message ein neuer Verbindungsaufbau erfolgen, sondern es sollen Sessions sein, bei denen die Verbindungen so lange bestehen, bis sie getrennt werden. Die Kommunikations soll nicht nach dem Schema Request mit Warten auf Response erfolgen, sondern einfach die Message senden, ohne Response. Zehn Bytes nach Amerika senden und dann auf ein OK warten bis man die nächste Message sendet, soll nicht sein. Wenn es Antworten gibt, dann sollen diese mit anderen dafür vorgesehenen Messages erfolgen.
Requirements für Verbindungen:
- sichere, dauerhafte Verbindungen mit Versenden von Messages ohne Warten auf Response
Requirements für den Router:
- die Messages haben eine Message ID. Der Router soll eine empfangene Message an alle Clients versenden, welche sich dafür registriert haben, Messages mit dieser Message ID zu empfangen
- der Router soll schnell sein und soll die Message nicht erst parsen, um daraus die Message ID zu extrahieren
- da es sich bei bei den Messages um mit JSON serialisierte Strings als Byte Array handelt, gedacht einer Python Funktion als Parameter zu übergeben, genügt es, die Messages mit readline zu lesen. Mehrmaliges Lesen in verschiedene Buffer ist daher nicht nötig.
Wenn man allerdings nicht mit readline arbeiten würde, könnte man auch Urlaubsbilder im JPEG Format übertragen oder MP3 Dateien.
Aber ich denke, wenn jemand so etwas tun will, soll er nicht den Router damit belasten, sondern über den Router von anderen Clients erfragen, wie er das dann ohne den Router tun kann. Und so etwas würde man dann wohl am Besten mit bereits existerenden Lösungen tun (weil sich da einige beschwert hatten, dass ich nicht bereits existierende Lösungen verwenden würde)
Lösung für die Verbindungen:
- Sicherheit: Verwendung von TCP
- Dauerhaft: Verbindung pro Client durch Verwendung von socketserver.ThreadingMixIn und durch eine Schleife, bis der Client die Verbindung beendet:
Code: Alles auswählen
while True:
message = self.rfile.readline()
if len(message) == 0: break
- Ohne Response sondern über Messages zum Client: die Clients haben einen Server. Pro Thread von socketserver.ThreadingMixIn wird eine socketVerbindung zum Client eröffnet.
Die erste Message eines Clients an den Router ist seine IP und Portadresse und der Router baut dann eine Socket Verbindung zum Server des Clients auf:
Code: Alles auswählen
message = str(self.rfile.readline().strip(), "utf-8")
json_message = json.loads(message)
receiver_address=(json_message[0],json_message[1])
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(receiver_address)
Lösung für den Router:
- Versenden von Messages an Clients: mit dem Routerkommando Message REGISTER senden Clients eine Liste der Message IDs an den Router, für die sie Messages empfangen wollen
- Message IDs ohne parsen: mit dem Routerkommando ID_REQUEST senden Clients eine Liste der Message IDs an den Router, für die sie Messages senden wollen. Der Router gibt den Clients dann eine Tupelliste zurück mit den Message IDs der Clients und vom Router generierten Message IDs dafür, welche die Clients für diese Messages an den Router verwenden und der Message voranstellen sollen. Die vom Router generierten Message IDs haben eine feste Länge – zur Zeit von vier Bytes. Und so erhält der Router dann die Message ID von einer an ihn gesendeten Message:
Code: Alles auswählen
message_id = message[0:4] # first 4 bytes are the message id
- Lesen ohne Queues und Bufferung: denn es genügt readline:
Nicht alle Messages erfolgen ohne Response. Routerkommandos etwa gibt es nach dem Prinzip einfach Senden oder mit Warten auf Response:
- Die Message REGISTER, mit der Clients Message IDs versenden, für die sie Messages erhalten wollen, ist ohne Response
- Die Message ID_REQUEST allerdings ist mit Response. Wäre sie es nicht und eine Anwendung würde unmittelbar nach ID_REQUEST bereits senden, bevor der Router geantwortet hat, dann würde die Message ins Leere gehen und verworfen werden. Daher wartet ID_REQUEST auf die Antwort des Routers. Und unmittelbar folgene Sendebefehle erreichen ihr Ziel, vorausgesetzt, es haben sich bereits Empfänger dafür registriert.