文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>.杂项 | python...03-pubsubhubbub 和 twisted 的 persistent...

.杂项 | python...03-pubsubhubbub 和 twisted 的 persistent...

时间:2010-08-09  来源:zhengyun_ustc

03-PubSubHubbub 和 twisted 的 Persistent connections 能力

郑昀 201005 隶属于《07.杂项》

关于上节《02-Twisted 构建 Web Server 的 Socket 长链接问题 》,还可以继续探讨为何会保持 Socket 长链接。

该关闭的连接没关闭?

有人在twisted邮件列表中也反映
『We close the render_POST with a request.write('data') & a request.finish() but the connection stays open』调用了request.finish(),socket连接依然保持着,这现象和我们遇到的一样。
twisted .web.server 里,Request 的 finish 函数是这么定义的:

def finish(self):
    http.Request.finish(self)
    for d in self.notifications:
        d.callback(None)
    self.notifications = []

它调用了 twisted.web.http 的 Request 类之 finish 方法:

def finish(self):
    """We are finished writing data."""
    if self.finished:
        warnings.warn("Warning! request.finish called twice.", stacklevel=2)
        return

    if not self.startedWriting:
        # write headers
        self.write('')

    if self.chunked:
        # write last chunk and closing CRLF
        self.transport.write("0\r\n\r\n")

    # log request
    if hasattr(self.channel, "factory"):
        self.channel.factory.log(self)

    self.finished = 1
    if not self.queued:
        self._cleanup()

可以看出 request.finish() 只是说要结束写数据了,把缓冲区内的数据都发送给对方,并没有去断开连接 ,否则就应该主动执行 self.transport.loseConnection() 。所以不主动断开socket连接也是设计使然。

PubSubHubbub 的持久连接

本来 PubSubHubbub 的 Hub 本来就是要保持长连接,从而重用连接。它的文档 PublisherEfficiency 上称:
『HTTP persistent connections and pipelining

By default in HTTP 1.1, TCP connections will be reused between requests. For a publisher serving many separate Atom feeds, this allows Hubs to get around the expense of creating a new TCP connection every time an event happens. Instead, Hubs MAY leave their TCP connections open and reuse them to make HTTP requests for freshly published events. 』

twisted.web.server 也支持持久连接

twisted.web.server 是支持 support persistent connections and pipelining 的。
文档指出
『Alternatively, they can return a special constant,twisted.web.server.NOT_DONE_YET, which tells the web server not to close the connection』即通过返回一个NOT_DONE_YET来告知Web Server不要关闭socket连接。 
所以会看到 Google Code 上不少代码都是在 render 函数内返回 server.NOT_DONE_YET 。

twisted.web.server.py 中, Request.render 函数定义中有这么一句判断:
if body == NOT_DONE_YET:
            return
...
self.finish()
也就是说如果你返回 NOT_DONE_YET ,就不会再调用 request.finish() 了。

这个 NOT_DONE_YET 标志有几种解释:

http://www.olivepeak.com/blog/posts/read/simple-http-pubsub-server-with-twisted 说:
『returns server.NOT_DONE_YET. This tells Twisted to not return anything to the client, but leave the connection open for later processing .』

http://www.ibm.com/developerworks/library/l-twist2.html?S_TACT=105AGX52&S_CMP=cn-a-l 则认为:
『The odd-looking return value server.NOT_DONE_YET is a flag to the Twisted server to flush the page content out of the request object.』

http://blog.csdn.net/gashero/archive/2007/03/02/1519045.aspx 说:
『你可以使用魔术值 twisted.web.server.NOT_DONE_YET ,可以告知Resource有些事情是异步的而且尚未完成,直到你调用了request.finish()。然后调用request.finish()直到写完了所有的响应数据。』

总之,不管如何解释,return server.NOT_DONE_YET from the render_GET/render_POST method, so the connection keeps open是没错的。

所以身为 PubSubHubbub Subscriber 角色的 Web Server ,我们的 render_POST 方法可以这么写:

# 处理 PubSubHubbub Hub 推送过来的数据
def render_POST(self, request):
    try:
            body = request.content.read()
            def finish_success(request):
                if(request._disconnected or request.finished):
                    print('***>This request is already finished.')
                    pass
                else:
                    print('***>This request wiil be finished.')
                    request.setResponseCode(http.NO_CONTENT)
                    request.write("")
                    request.finish()
            def finish_failed(request):
                print('-=->fail in parseData?')
            threads.deferToThread(self.parseData, body).addCallbacks(lambda x: finish_success(request), lambda x: finish_failed(request))
            """deferToThread 方法默认用 reactor.getThreadPool() 开辟的线程池。
            它调用这个线程池的 threadpool.callInThreadWithCallback
            方法,实际效果和 reactor.callInThread 一样。区别只是 deferToThread 可以返回一个 deferred ,能够 addCallback。
            """
    except:
        traceback.print_exc()
    request.setResponseCode(http.NO_CONTENT)#即204
    return NOT_DONE_YET

也就是,接收到 POST 过来的数据后,异步扔给另一个方法解析和处理,这厢立刻 return NOT_DONE_YET , 等处理成功了,回调里再 finish 掉当前的 request 。

参考资源:

1、关于Windows频繁打开关闭端口时出现的问题  ;

2、Choosing a TCP Port for a Network Service ;

3、02-Twisted 构建 Web Server 的 Socket 长链接问题 | 07.杂项 | Python  ;

4、03-PubSubHubbub 和 twisted 的 Persistent connections 能力 | 07.杂项 | Python  ;

5、Windows频繁打开和关闭端口可能引发的问题 | 07.杂项  。

相关阅读 更多 +
排行榜 更多 +
找茬脑洞的世界安卓版

找茬脑洞的世界安卓版

休闲益智 下载
滑板英雄跑酷2手游

滑板英雄跑酷2手游

休闲益智 下载
披萨对对看下载

披萨对对看下载

休闲益智 下载