捕获客户端断开连接事件!- Gevent/Python

7 投票
3 回答
2002 浏览
提问于 2025-04-16 01:50

我正在使用长轮询来实现一个聊天功能,使用的是gevent。 在等待新消息发送到聊天时,我使用了Event.wait()。


我想要处理客户端断开连接的情况,加一些功能:

比如说,给其他聊天用户返回“客户端已断开连接”的消息。


这样做可以吗?=)

3 个回答

1

这完全是我在瞎猜,因为我从来没有用过gevent。不过,我在想,客户端断开连接可能就是当套接字(socket)关闭的时候。所以,也许可以试试下面这样的代码:

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

根据WSGI PEP的规定,如果你的应用返回一个带有close()方法的迭代器,服务器在请求结束时应该调用这个方法。下面是一个例子:

"""
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()

不过,Python的wsgiref实现(还有从它继承的Django开发服务器)存在一个bug,这个bug导致在客户端中途断开连接时,close()方法不会被调用。因此,在这种情况下,最好避免使用wsgiref和Django开发服务器。

另外要注意的是,当客户端断开连接时,close()方法不会立即被触发。它会在你尝试向客户端发送消息时被调用,但因为连接已经断开而失败时才会发生。

1

这要看你使用的是哪个WSGI服务器。根据我所知道的,gevent.wsgi在客户端关闭连接时不会以任何方式通知你的处理程序,因为libevent-http不支持这个功能。不过,使用gevent.pywsgi应该是可以做到的。你可能需要启动一个额外的绿色线程来监控套接字的状态,并以某种方式通知运行处理程序的绿色线程,比如通过结束它。不过,我可能也漏掉了更简单的方法。

撰写回答