2013-11-21 43 views
0

我有一个使用bottlegevent.wsgi实现的小型异步服务器。有用于实现长轮询,看起来很像在bottle documentation“事件回调”示例程序:使用bottle和gevent.wsgi响应客户端断开连接?

def worker(body): 
    msg = msgbus.recv() 
    body.put(msg) 
    body.put(StopIteration) 

@route('/poll') 
def poll(): 
    body = gevent.queue.Queue() 
    worker = gevent.spawn(worker, body) 
    return body 

这里,msgbus是一个ZMQ sub插座。

这一切工作正常,但如果客户端打破,而 worker被封锁msgbus.recv(),这greenlet任务将挂起 围绕连接“永远”(当然,直到收到消息),并且将只 发现当它尝试发送一个 响应时关于断开连接的客户端。

我可以使用msgbus.poll(timeout=something)如果我不想阻止 永远在等待ipc消息,但我仍然无法检测到客户端 断开连接。

什么做的就是像给客户 插座的参考,这样我可以在某种selectpoll循环, 使用它,或者获得某种我greenlet内异步通知,但 我不确定如何用这些 框架(瓶和gevent)完成这些任何一项。

有没有办法获得客户端断开连接的通知?

回答

1

啊哈! wsgi.input变量,至少在gevent.wsgi之下,有一个rfile成员,它是一个类似文件的对象。这看起来并不是WSGI spec所要求的,所以它可能不适用于其他服务器。

有了这个,我能修改我的代码看起来是这样的:

def worker(body, rfile): 
    poll = zmq.Poller() 
    poll.register(msgbus) 
    poll.register(rfile, zmq.POLLIN) 

    while True: 
    events = dict(poll.poll()) 

    if rfile.fileno() in events: 
     # client disconnect! 
     break 

    if msgbus in events: 
     msg = msgbus.recv() 
     body.put(msg) 
     break 

    body.put(StopIteration) 

@route('/poll') 
def poll(): 
    rfile = bottle.request.environ['wsgi.input'].rfile 
    body = gevent.queue.Queue() 
    worker = gevent.spawn(worker, body, rfile) 
    return body 

而这个伟大的工程......

...除了在OpenShift,在那里你将不得不使用 alternate frontend端口8000支持websockets。

相关问题