В настоящее время я работаю над реализацией 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 не запускается на стороне клиента. Я подозреваю, что может быть проблема с тем, как я отправляю события или с настройкой потоков.
Мы будем очень признательны за любые идеи или предложения о том, как устранить неполадки и решить эту проблему. Спасибо!






Вы смешиваете потоки с eventlet. Eventlet — это однопоточная асинхронная платформа, поэтому вам нужно оставаться в основном потоке, чтобы все работало.
Относительно простое решение — обезьянье исправление стандартной библиотеки Python, чтобы многие потоковые/сетевые вызовы были заменены эквивалентами, совместимыми с гринлетами. Это понадобится вам не только для фонового потока, но и для того, чтобы Redis работал под эвентлетом.
Я не знаю, существуют ли какие-либо проблемы между eventlet и SQS. Зачем нужен ивентлет? Я бы прекратил его использовать, если это причинит вам проблемы.
Вместо использования потоков используйте eventlet.spawn, который будет работать. в server.py
def start_server():
eventlet.spawn(run_sqs)
eventlet.spawn(eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 5000)), app))
Спасибо, Мигель, за ответ, но когда я использовал обезьяний патч в приведенном выше коде и вместо потоковой обработки я использовал eventlet.spawn, но я получаю это исключение «Ошибка обработки сообщения SQS: превышена максимальная глубина рекурсии», у меня мало знаний Что касается Redis для решения этой проблемы, любые ссылки, которые помогут здесь, будут оценены по достоинству. или мне следует использовать greenlet вместо eventlet?