Проблема с отправкой данных с сервера Socket.IO клиенту на Python

В настоящее время я работаю над реализацией Socket.IO, используя Python с Socketio и eventlet для моего сервера и Socketio для моего клиента. Несмотря на успешные соединения между клиентом и сервером, я столкнулся с проблемой, когда данные, отправленные с сервера, не принимаются/не отображаются в консоли клиента.

Вот упрощенная версия моего сервера (server.py):

import socketio
import eventlet
from threading import Thread
import redis
import time

sio = socketio.Server()
app = socketio.WSGIApp(sio)

redis_conn = None


def initialize_redis_conn():
    global redis_conn
    if redis_conn is None:
        redis_conn = redis.StrictRedis(host='localhost', port=6379, decode_responses=True)
        print("redis connection init")


def insert_update_sid(sid, unique_id):
    """
    Inserts or updates the sid and uniqueId of the client into the Redis cache.
    """
    initialize_redis_conn()
    key = f"DATA_KEY_{unique_id}"
    expiry_in_seconds = 1800
    redis_conn.setex(key, expiry_in_seconds, sid)
    print("Data inserted into Redis successfully")


def get_sid_by_unique_id(unique_id):
    """
    Returns the sessionId (sid) of a client using the uniqueId.
    """
    initialize_redis_conn()
    print("fetching sid")
    key = f"DATA_KEY_{unique_id}"
    sid = redis_conn.get(key)
    if sid:
        print(f"Got sid {sid} using uid {unique_id}")
        return sid
    else:
        return None


def listen_sqs_queue():
    """
    this func is just to mimic the sqs, when sqs receives the message it should send that to client 
    """

    data = {
        "communicationStatus": "OKAY",
        "status": "Complete"
    }
    unique_id = "123789"
    if unique_id:
        print("inside sqs impl is : ", unique_id)
        sid = get_sid_by_unique_id(unique_id=unique_id)
        if sid:
            print("calling send response to client")
            send_response_to_client(sid, data)
            print(
                f"Response has been sent to the client with sessionId: {sid} and uniqueId : {unique_id}")
        else:
            print(f"Client not found for the given uniqueId: {unique_id}")


def send_response_to_client(sid, resp):
    """
    this func sends the response to the client
    """

    sio.emit('response_from_server', f'response : {resp}')
    print("data sent to client ")


@sio.event
def connect(sid, environ):

    print(f"client {sid} connected")
    print("sid type is: ", type(sid))
    token = environ.get('HTTP_TOKEN')
    sio.emit("acknowledge", "ack recevied from server", room=sid)
    if token:
        auth_status_code = 200
        if auth_status_code == 200:
            unique_id = "123789"
            # insert the sid and uniqueId into redis cache 
            insert_update_sid(sid, unique_id)


@sio.event
def disconnect(sid):
    """
    this is a disconnect event which disconnects the client from server
    """
    print(f"client {sid} disconnected")


def start_server():
    initialize_redis_conn()

    # Start the server in a separate thread
    # eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 5000)), app)


    sqs_listen_thread = Thread(target=listen_sqs_queue)
    sqs_listen_thread.start()

    server_thread = Thread(target=eventlet.wsgi.server(eventlet.listen(('localhost', 5000)), app))
    server_thread.start()


    sqs_listen_thread.join()
    server_thread.join()


if __name__ == '__main__':
    start_server()

И мой клиент (client.py):


import requests
import socketio

PORT = "5000"

IP = "localhost"

sio = socketio.Client()


@sio.event
def connect():
    print("connection established to server connect event")


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


@sio.event
def server_response(response):
    print("response from server recived")
    print(f"response received from server: {response}")


@sio.event
def acknowledge(ack):
    print(ack)


if __name__ == '__main__':
    data = {}
    stage = "dev"
    token = get_token(stage)
    token = "Radom_token"
    if token:
        print("Token has been generated.")

        url = f"http://{IP}:{PORT}"

        # sio.connect(url, transports=['websocket', 'polling'], headers = {'token': token})
        sio.connect(url=url)
        sio.wait()

    else:
        print("Token has not been generated ")

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

Мы будем очень признательны за любые идеи или предложения о том, как устранить неполадки и решить эту проблему. Спасибо!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
117
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы смешиваете потоки с eventlet. Eventlet — это однопоточная асинхронная платформа, поэтому вам нужно оставаться в основном потоке, чтобы все работало.

Относительно простое решение — обезьянье исправление стандартной библиотеки Python, чтобы многие потоковые/сетевые вызовы были заменены эквивалентами, совместимыми с гринлетами. Это понадобится вам не только для фонового потока, но и для того, чтобы Redis работал под эвентлетом.

Спасибо, Мигель, за ответ, но когда я использовал обезьяний патч в приведенном выше коде и вместо потоковой обработки я использовал eventlet.spawn, но я получаю это исключение «Ошибка обработки сообщения SQS: превышена максимальная глубина рекурсии», у меня мало знаний Что касается Redis для решения этой проблемы, любые ссылки, которые помогут здесь, будут оценены по достоинству. или мне следует использовать greenlet вместо eventlet?

user22982329 27.02.2024 19:15

Я не знаю, существуют ли какие-либо проблемы между eventlet и SQS. Зачем нужен ивентлет? Я бы прекратил его использовать, если это причинит вам проблемы.

Miguel Grinberg 29.02.2024 17:29
Ответ принят как подходящий

Вместо использования потоков используйте eventlet.spawn, который будет работать. в server.py

def start_server():
   eventlet.spawn(run_sqs)
   eventlet.spawn(eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 5000)), app))

Другие вопросы по теме