Flask-socketio не получает сообщение от клиента

Я пытаюсь написать базовую программу Socket.io, в которой клиент python (python-socketio [asyncio_client] 4.6.0) отправляет однострочное сообщение на сервер фляги (с Flask-SocketIO 4.3.1 и eventlet).

Кажется, что клиент подключается и отправляет сообщение правильно, но на сервере Flask нет вывода.

Код сервера:

from flask import Flask
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@socketio.on('connect')
def test_connect():
    print('connected')


@socketio.on('disconnect')
def test_disconnect():
    print('Client disconnected')

@socketio.on('message')
def handle_message(msg):
    print('Recieved',msg)

@socketio.on('json')
def handle_json(json):
    print(str(json))

if __name__ == '__main__':
    socketio.run(app,debug=True)

Код клиента:

    import asyncio
    import socketio
    
    sio = socketio.AsyncClient()
    
    @sio.event
    def connect():
        print('connection established')
    
    @sio.event
    def disconnect():
        print('disconnected from server')
    
    async def main():
        await sio.connect('http://localhost:5000')
        await sio.emit('message',data='detection')
        print('message sent')
        await sio.disconnect()
    
    if __name__ == '__main__':
        asyncio.run(main())

Выход сервера:

PS C:\Users\daksh\sih\sihPython> python .\test_socketio.py
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 101-561-255
(16664) wsgi starting up on http://127.0.0.1:5000
(16664) accepted ('127.0.0.1', 59497)
connected
127.0.0.1 - - [23/Jul/2020 20:38:42] "GET /socket.io/?transport=polling&EIO=3&t=1595516920.71801 HTTP/1.1" 200 367 0.004934
Client disconnected
127.0.0.1 - - [23/Jul/2020 20:38:42] "GET /socket.io/?transport=websocket&EIO=3&sid=88790300120f4b899e019ae7cc16ee87&t=1595516922.7757218 HTTP/1.1" 200 0 0.010027

Вывод клиента:

PS C:\Users\daksh\sih\sihPython> python .\socketio-client.py
connection established
message sent

Оператор печати из handle_message() отсутствует в выходных данных сервера.

Я прошел через несколько учебных пособий в Интернете, и я пробовал их с пространствами имен и без них. Не смогли понять, в чем дело.

Любая помощь приветствуется.

(Я использую Python 3.8.3 в Windows 10)

ОБНОВЛЕНИЕ: это сработает, если я изменю код клиента для использования socketio.Client() вместо AsyncClient(), однако мне нужно, чтобы клиент подключался с использованием AsyncClient.


person Dakshin    schedule 23.07.2020    source источник


Ответы (1)


Проблема в том, что ваш асинхронный клиент, очевидно, асинхронен, вы не можете просто отправить и выйти, потому что вы не даете фоновым задачам, поддерживающим протокол Socket.IO, время для выполнения своих задач.

Вот более надежная версия клиента, которая позволяет событию пройти до выхода:

import asyncio
import socketio

sio = socketio.AsyncClient()

@sio.event
async def connect():
    print('connection established')
    await sio.emit('message',data='detection', callback=done)
    print('message sent')

@sio.event
def disconnect():
    print('disconnected from server')

async def done():
    await sio.disconnect()

async def main():
    await sio.connect('http://localhost:5000')
    await sio.wait()

if __name__ == '__main__':
    asyncio.run(main())

Хитрость здесь в том, чтобы использовать обратный вызов для emit. Когда вызывается обратный вызов, вы уверены, что сообщение было доставлено, поэтому в этот момент можно безопасно отключиться.

person Miguel    schedule 24.07.2020
comment
Спасибо за пример @Miguel. Используя код сервера из OP и ваш код для клиента, я получаю сообщение об ошибке, которое содержит сообщение raise exceptions.BadNamespaceError( socketio.exceptions.BadNamespaceError: / is not a connected namespace. Unclosed client session и заканчивается на RuntimeError: Event loop is closed. Я не уверен, как заставить простой пример работать. - person fffrost; 06.01.2021
comment
@fffrost да, в коде в этом ответе есть дополнительная проблема, которую я тогда не видел. Вызов подключения также является асинхронным, вам нужно дождаться вызова обработчика подключения, прежде чем вы сможете выполнить его. Теперь я переместил излучение в обработчик подключения, чтобы решить эту проблему. - person Miguel; 07.01.2021