解決dropbox中國無法及時自動同步的問題
最近由于想要使用dropbox的多人協作功能,就發現dropbox不能自動同步其他機器上產生的文件變化,經過一番搜索,發現原來是gfw在作怪(gfw和gd的性質和用心我們心知肚明,就不在這里評價了)。月光博客發布了解決dropbox無法實時更新的問題分析了產生這個問題的原因并提出一個有效的解決方案。但是在使用時我發現,我找不到一個優良穩定的代理服務器,也沒工夫去學習privoxy軟件的配置和使用,而且我要將解決方案提供給我的合伙人,一個復雜的方案是不能接受的。經過一番研究,提出如下比較簡單的辦法。
分析
我發現dropbox向notify8發出的請求很簡單,回應也很簡單,一共有兩種:{"ret":"new"}和{"ret":"punt"}
分別表示云端有變化和無變化,然后客戶端考慮去下載文件列表并同步。
經過一番痛苦的失敗,我發現這個請求的其實是一個comet請求,服務器端并不馬上回應,而是會掛起,如果有變化,則馬上回應,如果一直沒有變化,大約一分鐘超時回應punt,然后客戶端再連接服務器。在我分析dropbox的過程中一直不解:為什么dropbox的其他請求都是https,而只有這一個請求是http的。現在找到了答案:因為它是comet請求,長連接,而且連接頻率非常高,如果使用https代價太大,而且影響效率。如果這個請求返回new,客戶端就會使用https連接服務器端。
解決
由此提出一個完美的解決方案,不僅可以解決本機的問題,而且可以解決朋友的問題,只要讓朋友修改hosts為我的ip地址:
- 修改hosts將notify8對應的ip地址改為本機
- 在本機建立一個http服務,代理notify8得到dropbox的返回值,再原封不動地返回給本機dropbox客戶端
具體方法是使用tornado,進行一步http請求,這樣只占用很少一部分系統資源。貼出代碼。
代碼
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
from tornado import httpclient
define("port", default=8888, help="run on the given port", type=int)
class application(tornado.web.application):
&&& def __init__(self):
&&&&&&& handlers = [
&&&&&&&&&&& (r"/subscribe", notifyhandler),
&&&&&&&&&&& (r"/.*", homehandler),
&&&&&&& ]
&&&&&&& settings = dict(
&&&&&&&&&&& debug=true,
&&&&&&& )
&&&&&&& self.debug = true
&&&&&&& tornado.web.application.__init__(self, handlers, **settings)
class homehandler(tornado.web.requesthandler):
&&& def get(self):
&&&&&&& self.set_header("content-type", "text/plain")
&&&&&&& self.write("hello from tornado!")
class notifyhandler(tornado.web.requesthandler):
&&& @tornado.web.asynchronous
&&& def get(self):
&&&&&&& self.set_header("content-type", "text/plain")
&&&&&&& url = xxxxx #關鍵代碼還是不貼出來了,人怕出名豬怕壯,要是大多數人會用了,估計這個方法死期不遠矣!
&&&&&&& http_client = httpclient.asynchttpclient()
&&&&&&& http_client.fetch(url, self.handle_response, request_timeout=100.0)
&&& def handle_response(self, response):
&&&&&&& if response.error:
&&&&&&&&&&& print "can not connect."
&&&&&&&&&&& self.write("{\"ret\": \"new\"}")
&&&&&&& else:
&&&&&&&&&&& print "connect successfull."
&&&&&&&&&&& self.write(response.body)
&&&&&&& self.finish()
def main():
&&& tornado.options.parse_command_line()
&&& http_server = tornado.httpserver.httpserver(application())
&&& http_server.listen(options.port)
&&& tornado.ioloop.ioloop.instance().start()
if __name__ == "__main__":
&&& main()
來源:投稿,原文鏈接。