python-socketio не всегда выдает при отслеживании загрузки файла на флеш-сервер

Я использую флеш-сервер для веб-сервисов RESTful и python-socketio для достижения двунаправленной связи между сервером и клиентом, чтобы отслеживать ход загрузки на серверной части.

Я беру переменную sio, объявленную в файле server.py, и передаю ее в качестве параметра в новый объект, который будет использовать ее для передачи клиенту определенных сообщений о том, как происходит загрузка файла на сервер.

sio = socketio.Server(async_mode='threading')
omics_env = None

@sio.on('init', namespace='/guardiome')
def init(sid, data):
    global omics_env

    if omics_env == None:
        omics_env = Environment(socket=sio)
        omics_env.conda.download_conda()
        omics_env.data_management.download_omics_data()

Проблема в том, что когда файл загружается на сервер Python, он отправляет клиенту сообщение каждый раз, когда записывает 1% данных в файл. Но он не всегда посылает клиенту каждый раз, когда он загружает / записывает 1 процент данных в файл.

Обычно он сообщает о прогрессе до 18%, задерживает на некоторое время, а затем отчитывается о 40%, пропуская выбросы между 18% и 40%.

Кто-то может сказать, что интернет, возможно, отстает, но я печатал операторы в функции загрузки поверх функции emit, которая показывает, что она записывает / загружает каждый 1 процент данных.

Я также проверил онлайн для другого ресурса. Некоторые упоминали использование eventlet и делали что-то подобное на самом высоком уровне кода сервера.

import eventlet
evenlet.monkey_patch()

Но это не приводит к генерации кода вообще.

Другие упоминали об использовании очереди сообщений, такой как redis, но я не могу использовать redis, и я планирую превратить весь код python в двоичный исполняемый файл, чтобы он был полностью переносимым на платформе linux для связи с локальным клиентом.

Вот мой server.py

import socketio
import eventlet.wsgi

from environment import Environment

from flask import Flask, jsonify, request, send_file
from flask_cors import CORS

omics_env = None

sio = socketio.Server(async_mode='threading')
app = Flask(__name__)
CORS(app)

@sio.on('init', namespace='/guardiome')
def init(sid, data):
    global omics_env

    if omics_env == None:
        omics_env = Environment(socket=sio)
        omics_env.conda.download_conda()
        omics_env.data_management.download_omics_data()

    omics_env.logger.info('_is_ready()')

    sio.emit(
        event='init',
        data={'status': True, 'information': None},
        namespace='/guardiome')


try:
    # wrap Flask application with engineio's middleware
    app.wsgi_app = socketio.Middleware(sio, app.wsgi_app)
    # Launch the server with socket integration
    app.run(port=8008, debug=False, threaded=True)

finally:
    pass
    # LOGGER.info('Exiting ...')

Вот функция download_w_progress, в которую я передаю sio в качестве параметра reporter

def download_w_progress(url , path, reporter=None):

    ssl._create_default_https_context = ssl._create_unverified_context
    r = requests.get(url, stream=True)

    # Helper lambda functions
    progress_report = lambda current, total: int((current/total)*100)
    raw_percent = lambda current, total: (current/total)*100

    # TODO(mak3): Write lambda function for reporting amount of file downloaded
    # in MB, KB, GB, or whatever

    with open(path, 'wb') as f:

        total_length = int(r.headers.get('content-length'))
        progress_count = 0
        chunk_size = 1024

        # Used to cut down on emit the same rounded percentage number
        previous_percent = -1

        # Read and write the file in chunks to its destination
        for chunk in r.iter_content(chunk_size=1024):
            progress_dict = {
                "percent": progress_report(progress_count, total_length)
            }

            if reporter != None:
                # Limit the number of emits sent to prevent
                # to socket from overworking
                if progress_dict["percent"] != previous_percent:
                    reporter.emit(event="environment", namespace="/guardiome", data=progress_dict)


            # TODO(mak3): Remove or uncomment in production
            if progress_dict["percent"] != previous_percent:
                print(progress_dict["percent"], end='\r')

            progress_count += chunk_size
            previous_percent = progress_dict["percent"]

            if chunk:
                f.write(chunk)
                f.flush()

0 ответов

Извините, я пропустил этот вопрос, когда вы его опубликовали.

В вашем коде есть пара проблем. Вы выбираете async_mode='threading, В общем случае лучше не указывать этот аргумент и позволить серверу выбирать лучший асинхронный режим в зависимости от сервера, который вы используете. Например, когда вы добавляете eventlet, режим работы с потоками не работает, на самом деле для Eventlet существует специальный асинхронный режим.

Поэтому я рекомендую:

  1. удалить async_mode аргумент в socketio.Server() конструктор
  2. установить eventlet в вашей виртуальной среде
  3. заменить app.run() раздел в вашем скрипте с кодом, который запускает сервер событий или если вы используете Flask, используйте расширение Flask-SocketIO, в которое уже встроен этот код.
  4. добавить sio.sleep(0) вызов внутри цикла, где вы читаете свой файл. Это даст eventlet возможность гладко выполнять все задачи.
Другие вопросы по тегам