2014-02-09 66 views
1

我正在嘗試創建Python智能代理服務器,它應該能夠將大量請求主體內容從客戶端傳輸到某些內部存儲區(可能是亞馬遜S3,Swift,ftp或類似的東西這個)。流媒體服務器應請求一些內部API服務器確定上傳到內部存儲的參數。主要限制是它應該在一個使用方法PUT的HTTP操作中完成。它也應該異步工作,因爲會有很多文件上傳。用於流式傳輸請求主體內容的Python服務器

什麼解決方案允許我從上載內容中讀取塊,並開始將此塊流式傳輸到內部存儲器befor用戶將上傳整個文件?在將管理權限交給wsgi applications/python web服務器之前,我會收到所有知道等待整個內容的python web應用程序。

我發現的解決方案之一是龍捲風叉https://github.com/nephics/tornado。但它是非官方的,龍捲風開發商不急於將其納入主要分支。 因此,您可能會對我的問題了解一些現有的解決方案嗎?龍捲風?扭曲? gevents?

+0

如果使用'urllib的任何具體問題'和一堆線程/ greenlets?或者這是一個普遍的「什麼是最好的解決方案」問題? – Carpetsmoker

+0

@Carpetsmoker看來我問錯了問題。我已澄清說明: 「什麼解決方案允許我從上載內容中讀取塊,並開始將此塊流式傳輸到內部存儲器,因爲用戶將上傳整個文件。我知道的所有解決方案都等待整個內容,然後再對wsgi應用程序進行管理/ python web server「 – Dmitry

回答

-2

看來我使用GEVENT庫和猴子修補了一個解決方案:

from gevent.monkey import patch_all 
patch_all() 
from gevent.pywsgi import WSGIServer 


def stream_to_internal_storage(data): 
    pass 


def simple_app(environ, start_response): 
    bytes_to_read = 1024 

    while True: 
     readbuffer = environ["wsgi.input"].read(bytes_to_read) 
     if not len(readbuffer) > 0: 
      break 
     stream_to_internal_storage(readbuffer) 

    start_response("200 OK", [("Content-type", "text/html")]) 
    return ["hello world"] 


def run(): 
    config = {'host': '127.0.0.1', 'port': 45000} 

    server = WSGIServer((config['host'], config['port']), application=simple_app) 
    server.serve_forever() 


if __name__ == '__main__': 
    run() 

它工作得很好,當我嘗試上傳大文件:

curl -i -X PUT --progress-bar --verbose --data-binary @/path/to/huge/file "http://127.0.0.1:45000" 
3

這裏的,它流與扭曲的編寫上傳處理服務器的例子:

from twisted.internet import reactor 
from twisted.internet.endpoints import serverFromString 

from twisted.web.server import Request, Site 
from twisted.web.resource import Resource 

from twisted.application.service import Application 
from twisted.application.internet import StreamServerEndpointService 

# Define a Resource class that doesn't really care what requests are made of it. 
# This simplifies things since it lets us mostly ignore Twisted Web's resource 
# traversal features. 
class StubResource(Resource): 
    isLeaf = True 

    def render(self, request): 
     return b"" 

class StreamingRequestHandler(Request): 
    def handleContentChunk(self, chunk): 
     # `chunk` is part of the request body. 
     # This method is called as the chunks are received. 
     Request.handleContentChunk(self, chunk) 
     # Unfortunately you have to use a private attribute to learn where 
     # the content is being sent. 
     path = self.channel._path 

     print "Server received %d more bytes for %s" % (len(chunk), path) 

class StreamingSite(Site): 
    requestFactory = StreamingRequestHandler 

application = Application("Streaming Upload Server") 

factory = StreamingSite(StubResource()) 
endpoint = serverFromString(reactor, b"tcp:8080") 
StreamServerEndpointService(endpoint, factory).setServiceParent(application) 

這是一個TAC文件(把它放在streamingserver.tac和運行twistd -ny streamingserver.tac)。

由於需要使用self.channel._path這不是一個完全支持的方法。 API的整體也相當笨拙,所以這是一個例子,它可能是比它好。長期以來,人們一直致力於使這種事情變得更加容易(http://tm.tl/288),但在此之前可能還需要很長時間。

+0

謝謝!我注意到這個解決方案是扭曲的。如你所願,你可能會看到我自己的解決方案,使用低於 – Dmitry

+0

的gevents感謝您分享您的解決方案! –

相關問題