Мне нужно немного понять, как работает модуль 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 () является брутальной. Это действительно насильственный способ убить процесс. Это работает, но я хочу что-то пифоническое и немного менее, ну, брутальное.
Я прошу прощения за неоднозначность моих вопросов. Я старался быть как можно более конкретным, но на самом деле это вопросы с большими идеями, а не о конкретных строках кода.