socketserver — Ein Framework für Netzwerksrealser¶
Quellcode: Lib/socketserver.py
Das Modul socketserver vereinfacht die Aufgabe der Erstellung von Netzwerksrealsern.
Verfügbarkeit: nicht WASI.
Dieses Modul funktioniert nicht oder ist nicht auf WebAssembly verfügbar. Weitere Informationen finden Sie unter WebAssembly-Plattformen.
Es gibt vier grundlegende konkrete Serverklassen
- class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)¶
Dies verwendet das Internet-TCP-Protokoll, das für kontinuierliche Datenströme zwischen Client und Server sorgt. Wenn bind_and_activate wahr ist, versucht der Konstruktor automatisch,
server_bind()undserver_activate()aufzurufen. Die anderen Parameter werden an die BasisklasseBaseServerübergeben.
- class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)¶
Dies verwendet Datagramme, die diskrete Informationspakete sind, die außer Reihenfolge ankommen oder während der Übertragung verloren gehen können. Die Parameter sind dieselben wie für
TCPServer.
- class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)¶
- class socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)¶
Diese seltener verwendeten Klassen ähneln den TCP- und UDP-Klassen, verwenden jedoch Unix-Domain-Sockets; sie sind auf Nicht-Unix-Plattformen nicht verfügbar. Die Parameter sind dieselben wie für
TCPServer.
Diese vier Klassen verarbeiten Anfragen synchron; jede Anfrage muss abgeschlossen sein, bevor die nächste Anfrage begonnen werden kann. Dies ist nicht geeignet, wenn jede Anfrage lange zur Fertigstellung benötigt, weil sie viel Berechnung erfordert oder weil sie viele Daten zurückgibt, die der Client nur langsam verarbeiten kann. Die Lösung besteht darin, einen separaten Prozess oder Thread zu erstellen, um jede Anfrage zu bearbeiten; die Mix-in-Klassen ForkingMixIn und ThreadingMixIn können verwendet werden, um asynchrones Verhalten zu unterstützen.
Die Erstellung eines Servers erfordert mehrere Schritte. Zuerst müssen Sie eine Anfragebehandlungsklasse erstellen, indem Sie von der Klasse BaseRequestHandler erben und ihre Methode handle() überschreiben; diese Methode wird eingehende Anfragen bearbeiten. Zweitens müssen Sie eine der Serverklassen instanziieren und ihr die Adresse des Servers und die Anfragebehandlungsklasse übergeben. Es wird empfohlen, den Server in einer with-Anweisung zu verwenden. Rufen Sie dann die Methode handle_request() oder serve_forever() des Serverobjekts auf, um eine oder mehrere Anfragen zu bearbeiten. Schließlich rufen Sie server_close() auf, um den Socket zu schließen (es sei denn, Sie haben eine with-Anweisung verwendet).
Wenn Sie von ThreadingMixIn für das Verhalten von Thread-Verbindungen erben, sollten Sie explizit deklarieren, wie Ihre Threads bei einem abrupten Herunterfahren reagieren sollen. Die Klasse ThreadingMixIn definiert ein Attribut daemon_threads, das angibt, ob der Server auf die Thread-Beendigung warten soll. Sie sollten das Flag explizit setzen, wenn Sie möchten, dass Threads autonom agieren; der Standardwert ist False, was bedeutet, dass Python erst beendet wird, wenn alle von ThreadingMixIn erstellten Threads beendet wurden.
Serverklassen haben dieselben externen Methoden und Attribute, unabhängig davon, welches Netzwerkprotokoll sie verwenden.
Hinweise zur Servererstellung¶
Es gibt fünf Klassen in einem Vererbungsdiagramm, von denen vier synchrone Server von vier Typen darstellen
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
Beachten Sie, dass UnixDatagramServer von UDPServer abgeleitet ist, und nicht von UnixStreamServer — der einzige Unterschied zwischen einem IP- und einem Unix-Server ist die Adressfamilie.
- class socketserver.ForkingMixIn¶
- class socketserver.ThreadingMixIn¶
Forking- und Threading-Versionen jeder Serverart können mit diesen Mix-in-Klassen erstellt werden. Zum Beispiel wird
ThreadingUDPServerwie folgt erstelltclass ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
Die Mix-in-Klasse kommt zuerst, da sie eine in
UDPServerdefinierte Methode überschreibt. Das Setzen der verschiedenen Attribute ändert auch das Verhalten des zugrunde liegenden Servermechanismus.ForkingMixInund die unten genannten Forking-Klassen sind nur auf POSIX-Plattformen verfügbar, diefork()unterstützen.- block_on_close¶
ForkingMixIn.server_closewartet, bis alle Kindprozesse abgeschlossen sind, es sei denn, das Attributblock_on_closeistFalse.ThreadingMixIn.server_closewartet, bis alle nicht-daemonischen Threads abgeschlossen sind, es sei denn, das Attributblock_on_closeistFalse.
- max_children¶
Geben Sie an, wie viele Kindprozesse gleichzeitig Anfragen für
ForkingMixInbearbeiten sollen. Wenn das Limit erreicht ist, warten neue Anfragen, bis ein Kindprozess beendet wurde.
- daemon_threads¶
Verwenden Sie für
ThreadingMixIndaemontische Threads, indem SieThreadingMixIn.daemon_threadsaufTruesetzen, um nicht auf den Abschluss von Threads zu warten.
Geändert in Version 3.7:
ForkingMixIn.server_closeundThreadingMixIn.server_closewarten jetzt, bis alle Kindprozesse und nicht-daemonischen Threads abgeschlossen sind. Ein neues KlassenattributForkingMixIn.block_on_closewurde hinzugefügt, um das Verhalten vor Version 3.7 zu aktivieren.
- class socketserver.ForkingTCPServer¶
- class socketserver.ForkingUDPServer¶
- class socketserver.ThreadingTCPServer¶
- class socketserver.ThreadingUDPServer¶
- class socketserver.ForkingUnixStreamServer¶
- class socketserver.ForkingUnixDatagramServer¶
- class socketserver.ThreadingUnixStreamServer¶
- class socketserver.ThreadingUnixDatagramServer¶
Diese Klassen sind vordefiniert und verwenden die Mix-in-Klassen.
Hinzugefügt in Version 3.12: Die Klassen ForkingUnixStreamServer und ForkingUnixDatagramServer wurden hinzugefügt.
Um einen Dienst zu implementieren, müssen Sie eine Klasse von BaseRequestHandler ableiten und ihre Methode handle() neu definieren. Sie können dann verschiedene Versionen des Dienstes ausführen, indem Sie eine der Serverklassen mit Ihrer Anfragebehandlungsklasse kombinieren. Die Anfragebehandlungsklasse muss für Datagramm- oder Stream-Dienste unterschiedlich sein. Dies kann durch die Verwendung der Handler-Unterklassen StreamRequestHandler oder DatagramRequestHandler verborgen werden.
Natürlich müssen Sie immer noch Ihren Verstand benutzen! Zum Beispiel ist es unsinnig, einen Forking-Server zu verwenden, wenn der Dienst einen Zustand im Speicher enthält, der von verschiedenen Anfragen geändert werden kann, da die Änderungen im Kindprozess nie den ursprünglichen Zustand im Elternprozess erreichen und an jedes Kind weitergegeben würden. In diesem Fall können Sie einen Threading-Server verwenden, aber Sie müssen wahrscheinlich Sperren verwenden, um die Integrität der gemeinsamen Daten zu schützen.
Wenn Sie hingegen einen HTTP-Server erstellen, bei dem alle Daten extern gespeichert sind (z.B. im Dateisystem), macht eine synchrone Klasse den Dienst im Wesentlichen "taub", während eine Anfrage bearbeitet wird – was sehr lange dauern kann, wenn ein Client die angeforderten Daten nur langsam empfängt. Hier ist ein Threading- oder Forking-Server angebracht.
In einigen Fällen kann es angebracht sein, einen Teil einer Anfrage synchron zu verarbeiten, die Verarbeitung aber in einem geforkten Kindprozess abzuschließen, abhängig von den Anfragedaten. Dies kann implementiert werden, indem ein synchroner Server verwendet und in der Methode handle() der Anfragebehandlungsklasse explizit geforkt wird.
Ein anderer Ansatz zur Verarbeitung mehrerer gleichzeitiger Anfragen in einer Umgebung, die weder Threads noch fork() unterstützt (oder wo diese zu teuer oder für den Dienst ungeeignet sind), besteht darin, eine explizite Tabelle von teilweise abgeschlossenen Anfragen zu pflegen und selectors zu verwenden, um zu entscheiden, welche Anfrage als nächstes bearbeitet werden soll (oder ob eine neue eingehende Anfrage bearbeitet werden soll). Dies ist besonders wichtig für Stream-Dienste, bei denen jeder Client potenziell lange verbunden sein kann (wenn keine Threads oder Unterprozesse verwendet werden können).
Serverobjekte¶
- class socketserver.BaseServer(server_address, RequestHandlerClass)¶
Dies ist die Oberklasse aller Serverobjekte im Modul. Sie definiert die unten angegebene Schnittstelle, implementiert aber nicht die meisten Methoden, was in Unterklassen geschieht. Die beiden Parameter werden in den entsprechenden Attributen
server_addressundRequestHandlerClassgespeichert.- fileno()¶
Gibt einen ganzzahligen Dateideskriptor für den Socket zurück, auf dem der Server lauscht. Diese Funktion wird am häufigsten an
selectorsübergeben, um das Überwachen mehrerer Server im selben Prozess zu ermöglichen.
- handle_request()¶
Verarbeitet eine einzelne Anfrage. Diese Funktion ruft die folgenden Methoden in der Reihenfolge auf:
get_request(),verify_request()undprocess_request(). Wenn die vom Benutzer bereitgestellte Methodehandle()der Handler-Klasse eine Ausnahme auslöst, wird die Methodehandle_error()des Servers aufgerufen. Wenn innerhalb vontimeoutSekunden keine Anfrage empfangen wird, wirdhandle_timeout()aufgerufen undhandle_request()kehrt zurück.
- serve_forever(poll_interval=0.5)¶
Bearbeitet Anfragen, bis eine explizite
shutdown()-Anfrage empfangen wird. Fragt alle poll_interval Sekunden nach der Beendigung ab. Ignoriert das Attributtimeout. Es ruft auchservice_actions()auf, das von einer Unterklasse oder einem Mix-in verwendet werden kann, um dienstspezifische Aktionen bereitzustellen. Beispielsweise verwendet die KlasseForkingMixInservice_actions(), um Zombie-Kindprozesse aufzuräumen.Geändert in Version 3.3: Der Aufruf von
service_actionswurde zur Methodeserve_foreverhinzugefügt.
- service_actions()¶
Dies wird in der Schleife von
serve_forever()aufgerufen. Diese Methode kann von Unterklassen oder Mix-in-Klassen überschrieben werden, um dienstspezifische Aktionen auszuführen, wie z.B. Aufräumarbeiten.Hinzugefügt in Version 3.3.
- shutdown()¶
Weist die Schleife von
serve_forever()an, anzuhalten und zu warten, bis sie dies tut.shutdown()muss aufgerufen werden, währendserve_forever()in einem anderen Thread läuft, sonst kommt es zu einem Deadlock.
- server_close()¶
Bereinigt den Server. Kann überschrieben werden.
- address_family¶
Die Protokollfamilie, zu der der Socket des Servers gehört. Häufige Beispiele sind
socket.AF_INET,socket.AF_INET6undsocket.AF_UNIX. Erben Sie von den TCP- oder UDP-Serverklassen in diesem Modul mit dem aufAF_INET6gesetzten Klassenattributaddress_family = AF_INET6, wenn Sie IPv6-Serverklassen wünschen.
- RequestHandlerClass¶
Die vom Benutzer bereitgestellte Anfragebehandlungsklasse; eine Instanz dieser Klasse wird für jede Anfrage erstellt.
- server_address¶
Die Adresse, auf der der Server lauscht. Das Format der Adressen hängt von der Protokollfamilie ab; siehe die Dokumentation des Moduls
socketfür Details. Für Internetprotokolle ist dies ein Tupel, das einen String mit der Adresse und eine Ganzzahl für die Portnummer enthält: z.B.('127.0.0.1', 80).
- socket¶
Das Socket-Objekt, auf dem der Server auf eingehende Anfragen lauscht.
Die Serverklassen unterstützen die folgenden Klassenvariablen
- allow_reuse_address¶
Ob der Server die Wiederverwendung einer Adresse zulässt. Dies ist standardmäßig auf
Falsegesetzt und kann in Unterklassen gesetzt werden, um die Richtlinie zu ändern.
- request_queue_size¶
Die Größe der Anfragewarteschlange. Wenn die Verarbeitung einer einzelnen Anfrage lange dauert, werden Anfragen, die ankommen, während der Server beschäftigt ist, bis zu
request_queue_sizeAnfragen in eine Warteschlange gestellt. Sobald die Warteschlange voll ist, erhalten weitere Anfragen von Clients die Fehlermeldung "Connection denied". Der Standardwert ist normalerweise 5, kann aber von Unterklassen überschrieben werden.
- socket_type¶
Der Socket-Typ, der vom Server verwendet wird;
socket.SOCK_STREAMundsocket.SOCK_DGRAMsind zwei gängige Werte.
- timeout¶
Timeout-Dauer in Sekunden oder
None, wenn kein Timeout gewünscht ist. Wennhandle_request()innerhalb des Timeout-Zeitraums keine eingehenden Anfragen erhält, wird die Methodehandle_timeout()aufgerufen.
Es gibt verschiedene Server-Methoden, die von Unterklassen von Basis-Serverklassen wie
TCPServerüberschrieben werden können; diese Methoden sind für externe Benutzer des Serverobjekts nicht nützlich.- finish_request(request, client_address)¶
Verarbeitet die Anfrage tatsächlich, indem
RequestHandlerClassinstanziiert und seinehandle()Methode aufgerufen wird.
- get_request()¶
Muss eine Anfrage vom Socket akzeptieren und ein 2-Tupel zurückgeben, das das *neue* Socket-Objekt für die Kommunikation mit dem Client und die Adresse des Clients enthält.
- handle_error(request, client_address)¶
Diese Funktion wird aufgerufen, wenn die Methode
handle()einer Instanz vonRequestHandlerClasseine Ausnahme auslöst. Die Standardaktion ist, den Traceback auf der Standardfehlerausgabe auszugeben und die Verarbeitung weiterer Anfragen fortzusetzen.Geändert in Version 3.6: Wird jetzt nur noch für Ausnahmen aufgerufen, die von der Klasse
Exceptionabgeleitet sind.
- handle_timeout()¶
Diese Funktion wird aufgerufen, wenn das Attribut
timeoutauf einen Wert ungleichNonegesetzt wurde und die Timeout-Periode abgelaufen ist, ohne dass Anfragen empfangen wurden. Die Standardaktion für Forking-Server besteht darin, den Status beendeter Kindprozesse zu sammeln, während diese Methode bei Threading-Servern nichts tut.
- process_request(request, client_address)¶
Ruft
finish_request()auf, um eine Instanz vonRequestHandlerClasszu erstellen. Falls gewünscht, kann diese Funktion einen neuen Prozess oder Thread zum Bearbeiten der Anfrage erstellen; die KlassenForkingMixInundThreadingMixIntun dies.
- server_activate()¶
Wird vom Konstruktor des Servers aufgerufen, um den Server zu aktivieren. Das Standardverhalten für einen TCP-Server ruft einfach
listen()auf dem Socket des Servers auf. Kann überschrieben werden.
- server_bind()¶
Wird vom Konstruktor des Servers aufgerufen, um den Socket an die gewünschte Adresse zu binden. Kann überschrieben werden.
- verify_request(request, client_address)¶
Muss einen booleschen Wert zurückgeben; wenn der Wert
Trueist, wird die Anfrage verarbeitet, und wenn erFalseist, wird die Anfrage abgelehnt. Diese Funktion kann überschrieben werden, um Zugriffskontrollen für einen Server zu implementieren. Die Standardimplementierung gibt immerTruezurück.
Geändert in Version 3.6: Unterstützung für das Protokoll des Kontextmanagers wurde hinzugefügt. Das Verlassen des Kontextmanagers entspricht dem Aufruf von
server_close().
Request Handler Objekte¶
- class socketserver.BaseRequestHandler¶
Dies ist die Oberklasse aller Request Handler Objekte. Sie definiert die untenstehende Schnittstelle. Eine konkrete Unterklasse von Request Handler muss eine neue Methode
handle()definieren und kann jede der anderen Methoden überschreiben. Für jede Anfrage wird eine neue Instanz der Unterklasse erstellt.- setup()¶
Wird vor der Methode
handle()aufgerufen, um alle erforderlichen Initialisierungsaktionen durchzuführen. Die Standardimplementierung tut nichts.
- handle()¶
Diese Funktion muss alle Arbeiten ausführen, die zur Bedienung einer Anfrage erforderlich sind. Die Standardimplementierung tut nichts. Mehrere Instanzattribute sind ihr verfügbar; die Anfrage ist als
requestverfügbar; die Client-Adresse alsclient_address; und die Serverinstanz alsserver, falls sie Zugriff auf serverspezifische Informationen benötigt.Der Typ von
requestist für Datagramm- oder Stream-Dienste unterschiedlich. Für Stream-Dienste istrequestein Socket-Objekt; für Datagramm-Dienste istrequestein Paar aus String und Socket.
- finish()¶
Wird nach der Methode
handle()aufgerufen, um alle erforderlichen Aufräumarbeiten durchzuführen. Die Standardimplementierung tut nichts. Wennsetup()eine Ausnahme auslöst, wird diese Funktion nicht aufgerufen.
- request¶
Das *neue*
socket.socketObjekt, das zur Kommunikation mit dem Client verwendet wird.
- client_address¶
Client-Adresse, die von
BaseServer.get_request()zurückgegeben wird.
- server¶
BaseServerObjekt, das zur Bearbeitung der Anfrage verwendet wird.
- class socketserver.StreamRequestHandler¶
- class socketserver.DatagramRequestHandler¶
Diese Unterklassen von
BaseRequestHandlerüberschreiben die Methodensetup()undfinish()und stellen die Attributerfileundwfilebereit.- rfile¶
Ein Dateiobjekt, von dem die Anfrage gelesen wird. Unterstützt die lesbare Schnittstelle von
io.BufferedIOBase.
- wfile¶
Ein Dateiobjekt, auf das die Antwort geschrieben wird. Unterstützt die schreibbare Schnittstelle von
io.BufferedIOBase.
Geändert in Version 3.6:
wfileunterstützt nun auch die schreibbare Schnittstelle vonio.BufferedIOBase.
Beispiele¶
Beispiel für socketserver.TCPServer¶
Dies ist die Serverseite
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
pieces = [b'']
total = 0
while b'\n' not in pieces[-1] and total < 10_000:
pieces.append(self.request.recv(2000))
total += len(pieces[-1])
self.data = b''.join(pieces)
print(f"Received from {self.client_address[0]}:")
print(self.data.decode("utf-8"))
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
# after we return, the socket will be closed.
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
Eine alternative Request Handler Klasse, die Streams verwendet (dateiähnliche Objekte, die die Kommunikation vereinfachen, indem sie die Standard-Datei-Schnittstelle bereitstellen)
class MyTCPHandler(socketserver.StreamRequestHandler):
def handle(self):
# self.rfile is a file-like object created by the handler.
# We can now use e.g. readline() instead of raw recv() calls.
# We limit ourselves to 10000 bytes to avoid abuse by the sender.
self.data = self.rfile.readline(10000).rstrip()
print(f"{self.client_address[0]} wrote:")
print(self.data.decode("utf-8"))
# Likewise, self.wfile is a file-like object used to write back
# to the client
self.wfile.write(self.data.upper())
Der Unterschied besteht darin, dass der Aufruf von readline() im zweiten Handler recv() mehrmals aufrufen wird, bis ein Zeilenumbruchzeichen gefunden wird, während der erste Handler eine recv()-Schleife verwenden musste, um Daten zu sammeln, bis er selbst einen Zeilenumbruch fand. Hätte er nur ein einziges recv() ohne die Schleife verwendet, hätte er nur das bisher vom Client empfangene zurückgegeben. TCP ist Stream-basiert: Daten kommen in der Reihenfolge an, in der sie gesendet wurden, aber es gibt keine Korrelation zwischen den send() oder sendall() Aufrufen des Clients und der Anzahl der recv() Aufrufe auf dem Server, die erforderlich sind, um diese zu empfangen.
Dies ist die Clientseite
import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(bytes(data, "utf-8"))
sock.sendall(b"\n")
# Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8")
print("Sent: ", data)
print("Received:", received)
Die Ausgabe des Beispiels sollte ungefähr so aussehen
Server
$ python TCPServer.py
127.0.0.1 wrote:
b'hello world with TCP'
127.0.0.1 wrote:
b'python is nice'
Client
$ python TCPClient.py hello world with TCP
Sent: hello world with TCP
Received: HELLO WORLD WITH TCP
$ python TCPClient.py python is nice
Sent: python is nice
Received: PYTHON IS NICE
Beispiel für socketserver.UDPServer¶
Dies ist die Serverseite
import socketserver
class MyUDPHandler(socketserver.BaseRequestHandler):
"""
This class works similar to the TCP handler class, except that
self.request consists of a pair of data and client socket, and since
there is no connection the client address must be given explicitly
when sending data back via sendto().
"""
def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print(f"{self.client_address[0]} wrote:")
print(data)
socket.sendto(data.upper(), self.client_address)
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
server.serve_forever()
Dies ist die Clientseite
import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
# SOCK_DGRAM is the socket type to use for UDP sockets
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# As you can see, there is no connect() call; UDP has no connections.
# Instead, data is directly sent to the recipient via sendto().
sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))
received = str(sock.recv(1024), "utf-8")
print("Sent: ", data)
print("Received:", received)
Die Ausgabe des Beispiels sollte exakt wie beim TCP-Server-Beispiel aussehen.
Asynchrone Mixins¶
Verwenden Sie die Klassen ThreadingMixIn und ForkingMixIn, um asynchrone Handler zu erstellen.
Ein Beispiel für die Klasse ThreadingMixIn
import socket
import threading
import socketserver
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def client(ip, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response))
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
with server:
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print("Server loop running in thread:", server_thread.name)
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()
Die Ausgabe des Beispiels sollte ungefähr so aussehen
$ python ThreadedTCPServer.py
Server loop running in thread: Thread-1
Received: Thread-2: Hello World 1
Received: Thread-3: Hello World 2
Received: Thread-4: Hello World 3
Die Klasse ForkingMixIn wird auf die gleiche Weise verwendet, außer dass der Server für jede Anfrage einen neuen Prozess starten wird. Nur auf POSIX-Plattformen verfügbar, die fork() unterstützen.