Matroids Matheplanet Forum Index
Moderiert von matph
Informatik » Programmieren » Socket Programmierung in python: Multi-Connection Server realisieren
Autor
Universität/Hochschule Socket Programmierung in python: Multi-Connection Server realisieren
Lucky_7
Wenig Aktiv Letzter Besuch: vor mehr als 3 Monaten
Dabei seit: 21.01.2018
Mitteilungen: 185
  Themenstart: 2019-10-11

Ich habe unter folgendem Link ein Tutorial zur Socket-Programmierung in Python gefunden: hier Hierbei wird folgender Code vorgestellt, der einen Server realisiert, welcher mehrere Client-Connections akzeptiert, ohne zu blocken. D.h., sobald ein Socket frei ist, hält der Server seine Arbeit nicht an, bis auf diesem Socket auch etwas geschieht, sondern beobachtet das Socket bis der Server die Meldung erhält, dass hier etwas geschieht. So verstehe ich das. Den Großteil des Codes verstehe ich inzwischen. Wichtig ist es zu verstehen, dass selectors.select() einen namedTuple zurückgibt, der sowohl das Socketobjekt (key.fileobj) als auch eine Maske mask enthält, die als eine Liste zu verstehen ist, in welcher die Einträge Auskunft darüber geben, ob das Socket "ready to read", "ready to write" "errors occurred" ist. Wenn nun also ein Socket "ready to read" ist, dann rufen wir die accept_wrapper() Funktion auf. Wenn ich es richtig verstehe, dann akzeptieren wir hier erst einmal die Verbindung. Dann registrieren wir das Socket erneut, d.h. wir beobachten wann das Socket "ready to read" oder "ready to write" ist. Außerdem merken wir uns die Adresse der Verbindung. Eigentlich dürfte es dann ja nicht allzu lange dauern, bis der Client uns hier auch tatsächlich eine Nachricht schickt. Sobald das geschieht, rufen wir service_connection() auf. Hier verstehe ich in dem Code nicht so recht, warum in den if-Bedingungen mask & ... steht. Genügt nicht jeweils die Bedingung if selectors.EVENT_READ oder WRITE ? Wir lesen immer nur 1024 bytes. Ich nehme an es gibt also ein receive-Buffer, der genau diese Größe hat. Dann müssen wir aber auch sicher stellen, dass der Client nicht mehr Daten auf einmal schickt, oder? Wenn dieser Buffer leer ist, dann schließen wir die Client Verbindung. Okay, also was ich etwas schwierig zu verstehen finde, ist: Sobald mein Client dem Server eine Nachricht schickt, die größer als 1024 Bytes ist, (oder Bits?), was geschieht dann im einzelnen? Ist der Überhang dann verloren? Das kann ich mir nicht vorstellen, weill dann diese if-Bedingung nicht viel Sinn ergibt: \sourceon python if recv_data: data.outb += recv_data \sourceoff Das ergibt doch nur dann Sinn, wenn recv_data mehrfach true wird. \sourceon python #!/usr/bin/env python3 import socket import selectors HOST = '127.0.0.1' PORT = 65432 sel = selectors.DefaultSelector() lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) lsock.bind((host, port)) lsock.listen() print('listening on', (host, port)) lsock.setblocking(False) sel.register(lsock, selectors.EVENT_READ, data=None) while True: events = sel.select(timeout=None) for key, mask in events: if key.data is None: accept_wrapper(key.fileobj) else: service_connection(key, mask) def accept_wrapper(sock): conn, addr = sock.accept() # Should be ready to read print('accepted connection from', addr) conn.setblocking(False) data = types.SimpleNamespace(addr=addr, inb=b'', outb=b'') events = selectors.EVENT_READ | selectors.EVENT_WRITE sel.register(conn, events, data=data) def service_connection(key, mask): sock = key.fileobj data = key.data if mask & selectors.EVENT_READ: recv_data = sock.recv(1024) # Should be ready to read if recv_data: data.outb += recv_data else: print('closing connection to', data.addr) sel.unregister(sock) sock.close() if mask & selectors.EVENT_WRITE: if data.outb: print('echoing', repr(data.outb), 'to', data.addr) sent = sock.send(data.outb) # Should be ready to write data.outb = data.outb[sent:] \sourceoff


   Profil
Folgende Antworten hat der Fragesteller vermutlich noch nicht gesehen.
Er/sie war noch nicht wieder auf dem Matheplaneten
__blackjack__
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 23.09.2021
Mitteilungen: 40
  Beitrag No.1, eingetragen 2021-09-26

@Lucky_7: „Dann registrieren wir das Socket erneut“ stimmt nicht. Zuerst wurde das Serversocket registriert das auf Verbindungen wartet. Wenn dann eine Verbindung zustande gekommen ist haben wir ein neues Socket für den Client der sich da verbunden hat. Das Serversocket ist immer noch da, damit sich dort weitere Clients verbinden können. Für die Kommunikation mit mehreren Clients braucht man ja ein Socket pro Client. `mask` finde ich als Namen unpassend, denn das ist eine Maske sondern das sind Flags. `selectors.EVENT_READ` & Co sind Masken, denn damit werden bestimmte Flags isoliert abgefragt. Und das muss man machen, also auf ``mask & selectors.EVENT_READ`` weil in `mask` mehr als ein Zustand zutreffen kann. Das Socketobjekt kann in einem Aufruf `service_connection()` sowohl bereit zum lesen, als auch bereit zum schreiben sein. Oder nur eines davon. Oder auch keines davon. Und man muss testen was alles zutrifft, und das entsprechend behandeln. ``recv(1024)`` liest nicht 1024 Bytes und es ist auch egal ob da ein Puffer dahinter steht und auch wie gross der ist. 1024 ist eine Obergrenze die *wir* hier vorgeben — mehr wollen wir nicht haben und mehr bekommen wir auch nicht. Wir können weniger bekommen. Wenn weniger Daten da sind, oder beispielsweise wenn es gar keinen Puffer gibt. Dann liefert jeder `recv()`-Aufruf nur 1 Byte. Und es gibt immer den Sonderfall, das gar keine Daten gelesen werden, dann weiss man, dass die Gegenseite die Verbindung geschlossen hat, und das da auch nichts mehr kommen wird. Wir müssen als Empfänger nichts sicherstellen was der Sender macht. Darum kümmert sich das TCP-Protokoll. Der kann nicht ”zu viel senden”. In dem Fall sorgt der TCP/IP Stack dafür, dass der Sender blockiert. Oder eben entsprechend kein EVENT_WRITE bekommt um Daten abzusetzen, wenn der auch mit `select()` arbeitet. TCP verliert nichts. Das was auf der einen Seite reingesteckt wird, kommt auf der anderen Seite in der gleichen Reihenfolge wieder heraus. Was immer gerne falsch verstanden, und in Beispielen im Netz falsch gemacht wird, ist dass das was auf der einen Seite in einem Aufruf reingesteckt wird, auf der anderen Seite auch in einem Aufruf rauskommen würde. Das ist ”dummerweise” bei einer Verbindung mit "localhost" fast immer so, und auch oft in einem lokalen Netz in dem sonst nicht viel los ist, aber das ist eben nicht garantiert. Empfängercode muss im Extremfall damit klar kommen können, dass jeder `recv()`-Aufruf nur ein einzelnes Byte liefert.


   Profil

Wechsel in ein anderes Forum:
 Suchen    
 
All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest © 2001-2021 by Matroids Matheplanet
This web site was originally made with PHP-Nuke, a former web portal system written in PHP that seems no longer to be maintained nor supported. PHP-Nuke is Free Software released under the GNU/GPL license.
Ich distanziere mich von rechtswidrigen oder anstößigen Inhalten, die sich trotz aufmerksamer Prüfung hinter hier verwendeten Links verbergen mögen.
Lesen Sie die Nutzungsbedingungen, die Distanzierung, die Datenschutzerklärung und das Impressum.
[Seitenanfang]