03-PubSubHubbub 和 twisted 的 Persistent connections 能力 | 07.雜項 | Python

來源:互聯網
上載者:User
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.雜項 。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.