设为首页 收藏本站
查看: 1372|回复: 0

[经验分享] 03-PubSubHubbub 和 twisted 的 Persistent connections 能力 | 07.杂项 | Python

[复制链接]

尚未签到

发表于 2015-4-28 05:25:40 | 显示全部楼层 |阅读模式
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.iyunv.com/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.杂项 。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-61280-1-1.html 上篇帖子: python资料 下篇帖子: (转)Python 开源项目大杂烩
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表