Требуется понимание относительно веб-сокетов Python - PullRequest
0 голосов
/ 15 января 2019

Мне нужно немного понять, как работает модуль websockets в python. У меня есть суть, но есть несколько вещей, с которыми у меня проблемы. Я хочу сначала проверить свое понимание, а затем задать несколько конкретных вопросов.

Кстати, первый раз.

Я понимаю, что веб-сокеты (это веб-сокеты, а не веб-сокеты) полагаются на asyncio, и у меня есть достаточно приличное понимание того, как все это работает.

Для целей этого вопроса объяснение open_browser внутри питона не требуется.

В приведенном ниже коде я вижу последовательность событий.

1) websockets.serve () создает какой-либо объект сервера. receive_input - функция обработчика, которую нужно запустить.

2) asyncio.run_until_complete [(receive_input)] на самом деле не запускает сервер, а регистрирует его как нечто, запускаемое в цикле событий. asyncio и .serve умны, и знают, что нужно отключить цикл, когда сокет закрывается с обоих концов. (Какое-то исключение ServerConnectionClosed или что-то в этом роде)

3) asyncio.run_forever запускается и пропускает цикл событий. Функция receive_input несколько раз срабатывает, пока соединение не будет закрыто.

4) Функция receive_input принимает входные данные.

5) Откроется окно браузера.

6) Окно браузера закрывается. Сообщение отправляется обратно в python с требованием выйти.

7) Python получает команду quit и запускает процедуры выхода.

8) Python выходит.

Питон

import asyncio, json, websockets

open_browser.open()

async def receive_input( web_socket, path ):

    web_socket = web_socket #<------ Question #1

    async for input_from_javascript in web_socket: await 
        handle_input( web_socket, input_from_javascript )

async def handle_input( input_from_javascript )

    input_from_javascript = json.loads( input_from_javascript );

    if input_from_javascript[ 'key' ] == 'on_window_unload': 
        on_window_unload( input_from_javascript )

def on_window_unload( web_socket, input_from_javascript ):
        #Question #2

    web_socket.close(); kill(); sys.exit()

def kill( port=9000 ):
        Question #4

    os.system( 'kill -9 $(lsof -t -i:' + str( port ) + ')' )

kill(); open_browser()

start_server = websockets.serve( receive_input, '0.0.0.0', 9000 )

asyncio.get_event_loop().run_until_complete( start_server )
asyncio.get_event_loop().run_forever()

JavaScript

var web_socket = null;

window.onload = function( event ) {

    web_socket = new WebSocket( 'ws://0.0.0.0:9000' );

}

window.onbeforeunload = function() {

    web_socket.send( JSON.stringify( { 'key': 'on_window_unload' } ) );

};

Вопрос 1. Мне нужно определить мою переменную web_socket как глобальную переменную, доступную для других функций в модуле без передачи в качестве переменной. Мое текущее решение работает, но выглядит не очень хорошо. Есть ли способ, которым я могу определить переменную web_socket вне многократно работающей обслуживающей функции receive_input?

Вопрос 2. Моя функция on_window_unload не всегда срабатывает. Иногда процесс python просто продолжает работать. Каковы возможные причины этого? Очевидно, что если я захочу развернуть это, у меня не будет утечки памяти.

Вопрос 2a: Я полагаю, причина, по которой эта функция никогда не срабатывает, заключается в том, что сообщение on_window_unload каким-то образом теряется. Должен ли я создать функцию безопасности, которая может проверять, возможно, раз в секунду, чтобы увидеть, работает ли websocket на стороне javascript, и принудительно завершить работу, если это необходимо? Какую форму это примет, по крайней мере.

Вопрос 3: Иногда я получаю сообщение об ошибке сломанной трубы. Может быть, один из каждых 20 выстрелов, которые мне сказали, это сломанная труба. Я надеюсь, что это связано с тем, что при предыдущем запуске кода произошла ошибка, в результате чего процедура quit не была запущена, и поэтому сокет все еще занят, поэтому, когда все сказано и выполнено, а код свободен от ошибок, это победило ' это не проблема. Я надеюсь на это, потому что альтернатива в том, что веб-сокеты нестабильны по своей природе, и я не могу им доверять.

Вопрос 4: Убить процесс. Если я попытаюсь получить доступ к «0.0.0.0:9000» слишком быстро после выхода из исходного процесса, я получаю сообщение об ошибке «сокет уже используется». Это связано с тем, что порт не освобождается сразу после закрытия браузера. Кое-что о том, чтобы держать его открытым на случай, если клиент потерял связь на микросекунду, и держать его открытым, чтобы избежать перезагрузки страницы. Это означает, что мне нужно явно закрыть порт при закрытии окна. Я знаю где-то по пути, как я могу использовать флаг ReuseAddr (или что-то еще) на сервере, чтобы сделать закрытие порта - практически мгновенным -. По сути, как я могу мгновенно закрыть веб-сокет на обоих концах при закрытии окна, чтобы он сразу мог использоваться для следующего включения.

Вопрос 4a): функция kill () является брутальной. Это действительно насильственный способ убить процесс. Это работает, но я хочу что-то пифоническое и немного менее, ну, брутальное.

Я прошу прощения за неоднозначность моих вопросов. Я старался быть как можно более конкретным, но на самом деле это вопросы с большими идеями, а не о конкретных строках кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...