SocketServer serve_forever() beenden

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Hallo,

Ich habe zwar ähnliche Thread über die Suche gefunden, allerdings keine Lösung für meinen Code in python 2.7. Folgendes Problem:

Ich habe einen TCP-SocketServer erstellt und eine eigene Klasse in der ich handle() überschreibe. Den Server starte ich mittels server_forever(), der Server soll so lange requests bearbeiten, bis er den String "EOS_LM" in einer Nachricht über das Socket erhält. Dann soll der Server gestoppt werden. Shutdown() funktioniert leider nicht und wenn ich versuche aus handle() einen Wert mittels return zurückzugeben gelingt das auch nicht. Daher 2 Fragen:

1) Wie kann ich den Server beim Eintreffen eines Strings beenden
2) Wie kann ich Werte mittels return aus handle() zurückgeben

Danke schon mal im Voraus, lG dh233

Code: Alles auswählen

#!/usr/bin/python

import SocketServer
import json

class MyTCPHandler(SocketServer.BaseRequestHandler):
    """
    The RequestHandler 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.
    """

    SocketServer.TCPServer.allow_reuse_address = True
    
    def handle(self):
        self.data = self.request.recv(1024).strip()
        self.json = json.loads(self.data)
        print type(self.json)
        for keys,values in self.json.items():
            print values
        if (values in "EOS_LM"):
            return values
   
if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
    
    try:
        print "starting server forever"
        server.serve_forever()
    except KeyboardInterrupt:
        server.shutdown()
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@dh233: erstens läuft der Server so lange, bis Du shutdown auf dem Server-Objekt aufrufst. Und zweitens kannst Du bei handle gar nichts zurückgeben. Wohin soll denn das gegeben werden?
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Ja, da hast du Recht. Wie mache ich es aber nun am besten, dass der SocketServer solange Requests vom Client entgegen nimmt bis der String "EOS_LM" in der Message vom Client enthalten ist. In diesem Fall soll der Server dann beendet werden.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@dh233: wie wär's mit

Code: Alles auswählen

    def handle(self):
        [...]
        self.server.shutdown()
?
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Habe ich schon probiert, da blockt dann das ganze Programm. Wenn self.server.shutdown() funktionieren würde hätte ich genau das was ich will:

Code: Alles auswählen

def handle(self):
        self.data = self.request.recv(1024).strip()
        self.json = json.loads(self.data)
        print type(self.json)
        for keys,values in self.json.items():
            print values
        if (values in "EOS_LM"):
            self.server.shutdown()
BlackJack

@dh233: Was meinst Du mit „da blockt das gesamte Programm”? Der Code sieht auch sehr eigenartig aus. Dir ist klar das Wörterbücher keine bestimmte Reihenfolge haben, es also Zufall ist welchen Wert aus dem Wörterbuch nach der Schleife an `values` gebunden ist!? Und das an der Stelle ein `NameError` lauert wenn das Wörterbuch leer sein sollte und `values` deswegen gar nicht gebunden wird!? Und was ist `values` überhaupt? Wenn das *keine* Zeichenkette ist, dann ist die ``if``-Bedingung *niemals* wahr.

Die Klammern um die Bedingung ist überflüssig.

Und das `recv()` ist so nicht robust. Das übliche Problem: es ist nur garantiert das mindestens *ein* Byte gelesen wird. Wenn der Code nicht so geschrieben ist, dass er die Nachricht vom Client notfalls Byte für Byte empfangen kann, dann ist das ein Programmierfehler.
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

@BlackJack: Ja, der Code ist nur schnell zusammenkopiert und die restlichen Probleme sind mir auch bekannt. Mir geht es eher darum das geschilderte Problem zu lösen, um zu sehen, dass dieser Weg brauchbar ist. Danach können die von dir angesprochenen Verbesserungen vorgenommen werden. Auf jeden Fall Danke dafür.

Mit "das Programm block" meine ich, dass sich nichts mehr tut bis ich den Client händisch mit CTRL+C abbreche.
BlackJack

@dh233: Wird denn im Handler tatsächlich `shutdown()` aufgerufen? Die Bedingung sieht mir sehr Suspekt aus. Was sollte `values` denn an der Stelle für einen Wert haben?
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

@BlackJack: Ja, "shutdown()" wird aufgerufen. Ein Client schickt ein dict, das dann nach json konvertiert wird, values enthält dann "EOS_LM" und die if-Schleife wird betreten. Sieht man auch deutlich im debugger bzw. hatte ich auch schon ein einfaches "print" in der Schleife, um es mit zu verfolgen.
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Ich habe jetzt "SocketServer.ThreadingMixIn" verwendet, also eine Threaded-Variante. Nun funktioniert auch "self.server.shutdown()" wie erwartet:

Code: Alles auswählen

server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
Antworten