3

http ポスト経由で大きなファイルを受信できるようにする必要があるチェリーピー Web サーバーがあります。現時点では何かが機能していますが、送信されるファイルが大きくなりすぎると失敗します (約 200 MB)。curl を使用してテスト投稿リクエストを送信していますが、大きすぎるファイルを送信しようとすると、curl は「リクエストで送信されたエンティティが最大許容バイト数を超えています」と吐き出します。調べてみると、これはcherrypyのエラーのようです。

それで、送信されるファイルをチャンクで送信する必要があると思いますか? mmapで何かを試しましたが、うまくいきませんでした。ファイルのアップロードを処理するメソッドも、チャンクでデータを受け入れることができる必要がありますか?

4

2 に答える 2

7

私はDirectToDiskFileUpload出発点として取りました。大きなアップロードを処理するために行う変更は次のとおりです。

  1. server.max_request_body_size0(デフォルト 100MB)、
  2. server.socket_timeout60(デフォルトは 10 秒)、
  3. response.timeout3600(デフォルトは 300 秒)、
  4. を使用して二重コピーを回避しtempfile.NamedTemporaryFileます。

cgi.FieldStorageまた、アップロードをメモリに保持することを回避するために、標準の CherryPy 本体処理を無効にし、代わりに手動で使用するという無駄なアクションもいくつか行われています。あるからダメcherrypy._cpreqbody.Part.maxrambytes

Partがそのデータを文字列ではなくファイルに保存するまでのバイト数のしきい値。cgiPython の標準ライブラリのモジュールと同様に、デフォルトは 1000です。

次のコード (Python 2.7.4、CherryPy 3.6 で実行) と 1.4GB のファイルを試しました。メモリ使用量 ( gnome-system-monitor で) が 10MiB に達したことはありません。実際にディスクに書き込まれたバイト数によると、はほぼファイルのサイズですcat /proc/PID/iowrite_bytes標準cherrypy._cpreqbody.Partで、shutil.copyfileobj明らかに2倍です。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import os
import tempfile

import cherrypy


config = {
  'global' : {
    'server.socket_host' : '127.0.0.1',
    'server.socket_port' : 8080,
    'server.thread_pool' : 8,
    # remove any limit on the request body size; cherrypy's default is 100MB
    'server.max_request_body_size' : 0,
    # increase server socket timeout to 60s; cherrypy's defult is 10s
    'server.socket_timeout' : 60
  }
}


class NamedPart(cherrypy._cpreqbody.Part):

  def make_file(self):
    return tempfile.NamedTemporaryFile()

cherrypy._cpreqbody.Entity.part_class = NamedPart


class App:

  @cherrypy.expose
  def index(self):
    return '''<!DOCTYPE html>
      <html>
      <body>
        <form action='upload' method='post' enctype='multipart/form-data'>
          File: <input type='file' name='videoFile'/> <br/>
          <input type='submit' value='Upload'/>
        </form>
      </body>
      </html>
    '''

  @cherrypy.config(**{'response.timeout': 3600}) # default is 300s
  @cherrypy.expose()
  def upload(self, videoFile):
    assert isinstance(videoFile, cherrypy._cpreqbody.Part)

    destination = os.path.join('/home/user/', videoFile.filename)

    # Note that original link will be deleted by tempfile.NamedTemporaryFile
    os.link(videoFile.file.name, destination)

    # Double copy with standard ``cherrypy._cpreqbody.Part``
    #import shutil
    #with open(destination, 'wb') as f:
    #  shutil.copyfileobj(videoFile.file, f)

    return 'Okay'


if __name__ == '__main__':
  cherrypy.quickstart(App(), '/', config)
于 2014-10-10T12:26:57.707 に答える
0

巨大なファイルのアップロードは常に問題になります。アップロードの途中で接続が切れたらどうしますか? 代わりに、チャンク ファイルのアップロード方法を使用してください。

于 2014-10-10T12:31:03.240 に答える