2010-07-26 9 views
7

Ich benutze lange Polling für einen Chat mit Gevent. Ich verwende Event.wait(), wenn ich darauf warte, dass neue Nachrichten im Chat gepostet werden.Erfassen des Ereignisses beim Trennen des Clients! - Gevent/Python


Ich möchte die Gelegenheit behandeln ein Client trennt mit etwas Funktionalität:

z.B. Return "Client wurde getrennt" als eine Nachricht für andere Chat-Benutzer


Ist das möglich? =)

Antwort

1

Dies hängt davon ab, welchen WSGI-Server Sie verwenden. AFAIK gevent.wsgi wird Ihren Handler in keiner Weise benachrichtigen, wenn der Client die Verbindung schließt, da Libevent-http das nicht tut. Mit gevent.pywsgi sollte es jedoch möglich sein. Sie müssen wahrscheinlich ein zusätzliches Greenlet starten, um den Socket-Zustand zu überwachen und irgendwie das Greenlet, das den Handler ausführt, zu benachrichtigen, z. indem du es tötest. Ich könnte jedoch einen einfacheren Weg vermissen, dies zu tun.

+0

Vielen Dank für Ihren Gedanken, ich schätze es wirklich. Das würde ich wirklich gerne wissen! =) #gevent auf Freenode scheint in diesen Tagen ziemlich still ... Danke für deine Antwort Denis! – RadiantHex

+0

Ich frage mich, wäre es eine schreckliche Idee, eine Ausnahme in der WSGI-Anwendung asynchron zu lösen, wenn ein Client die Verbindung getrennt hat? –

1

Das ist ein totaler Stich im Dunkeln, da ich noch nie gevent benutzt habe aber einen Client nicht einfach trennen würde, wenn der Socket geschlossen ist. Also könnte so etwas funktionieren:

if not Event.wait(): 
    # Client has disconnected, do your magic here! 
    return Chat({'status': 'client x has disconnected'}) 
+0

Sie könnten einen Ninja mit diesem Stich geschlagen haben, lassen Sie mich überprüfen! = D Danke dafür! – RadiantHex

3

Laut der WSGI PEP, wenn Ihre App einen Iterator mit einer close() -Methode zurückgibt, sollte der Server das am Ende der Anfrage aufrufen. Hier ein Beispiel:

""" 
Run this script with 'python sleepy_app.py'. Then try connecting to the server 
with curl: 

    curl -N http://localhost:8000/ 

You should see a counter printed in your terminal, incrementing once every 
second. 

Hit Ctrl-C on the curl window to disconnect the client. Then watch the 
server's output. If running with a WSGI-compliant server, you should see 
"SLEEPY CONNECTION CLOSE" printed to the terminal. 
""" 

class SleepyApp(object): 
    def __init__(self, environ, start_response): 
     self.environ = environ 
     self.start_response = start_response 

    def __iter__(self): 
     self.start_response('200 OK', [('Content-type', 'text/plain')]) 
     # print out one number every 10 seconds. 
     import time # imported late for easier gevent patching 
     counter = 0 
     while True: 
      print "SLEEPY", counter 
      yield str(counter) + '\n' 
      counter += 1 
      time.sleep(1) 

    def close(self): 
     print "SLEEPY CONNECTION CLOSE" 


def run_gevent(): 
    from gevent.monkey import patch_all 
    patch_all() 
    from gevent.pywsgi import WSGIServer 
    server = WSGIServer(('0.0.0.0', 8000), SleepyApp) 
    print "Server running on port 0.0.0.0:8000. Ctrl+C to quit" 
    server.serve_forever() 

if __name__ == '__main__': 
    run_gevent() 

Allerdings gibt es a bug in Python wsgiref Implementierung (und im Django Dev-Server, die von ihr erbt), die nahe verhindert() von auf der Mitte des Stromes Client die Verbindung trennt genannt zu werden. Vermeiden Sie daher wsgiref und den Django-Dev-Server für diesen Fall.

Beachten Sie außerdem, dass close() nicht sofort ausgelöst wird, wenn der Client die Verbindung trennt. Es wird passieren, wenn Sie versuchen, eine Nachricht an den Client zu schreiben und scheitern, weil die Verbindung nicht mehr da ist.