django Socket IO中的同步问题

tct7dpnv  于 8个月前  发布在  Go
关注(0)|答案(2)|浏览(74)

我用python-socketio和socket.io-client实现了一个网站聊天。
有时候,当我们在不同的浏览器中同时打开多个标签,或者与同一个登录用户进行匿名会话时,新打开的标签可以成功地发送和接收消息。但是,旧的标签可以发送但不能接收消息,即使它们仍然连接到Python Socket.IO和socket.io-client。此外,我已经使用了一个房间会话来管理连接。这个问题发生在一个实时服务器上,在任何时候都有大约50-100个用户连接到套接字,而不是在本地主机上。

我使用的版本如下:

python-socketio==5.9.0
uvicorn==0.16.0
eventlet==0.33.3
socket.io-client = 4.7.2

字符串

后台:

import socketio
    sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins='*', logger=True, engineio_logger=True)
    connected_users = {}
    room_user_count = {}
    @sio.on("connect")
    async def connect(sid, environ):
      try:
        query_string = environ.get("QUERY_STRING") or "Anonymous"
        if query_string:
          username = query_string.split("username=")[1].split("&")[0]
          await sio.save_session(sid, {'username': username})
          room_name = await change_group_name(username)
          sio.enter_room(sid, room_name)
        print(f"[Connected] {sid}")
      except Exception as e:
        print("Connected error", str(e))
    @sio.on("login")
    async def handle_login(sid, data):
      username = data.get("username")
      session_id = await sio.get_session(sid)
      connected_users[sid] = {"username": username, "session_id": session_id['username']}
      print(f"{username} logged in.")
    @sio.on("disconnect")
    async def disconnect(sid):
      try:
        username = connected_users.get(sid, {}).get("username", "Anonymous")
        connected_users.pop(sid, None)
        leave_room = await change_group_name(username)
        sio.leave_room(sid, leave_room)
        print(f"Disconnected: {sid}, Username: {username}")
      except Exception as e:
        print(f"Disconnected Error: {e}")
    @sio.on("client_chat_app")
    async def message_from_client(sid, data):
      username = connected_users.get(sid, {}).get("username", "Anonymous")
      user = await get_user_obj(username)
      await chat_app_function(data, user, sid)

前端:

import socketIOClient from "socket.io-client";
useEffect(() => {
  let username = “username”;
  socket = socketIOClient(WEB_SOCKET_IO, {
   query: { username: username },
   secure: true,
   transports: ["websocket"],
   path: "/socket.io/",
   reconnectionDelay: 1000,
   reconnection: true,
   reconnectionAttempts: Infinity,
  });
  socket.on("connect", () => {
   socket.emit("login", { username });
  });
  let event_chat_app = username + "sent_chat_app";
  socket.on(event_chat_app, (value) => {
   try {
    console.log(“value”, value)
   } catch (e) {}
  });
 }
 return () => {
  socket?.disconnect();
 };
}, []);


我可以做些什么来确保同步问题不再发生?

nhhxz33t

nhhxz33t1#

如果旧标签可以发送消息但不能接收消息,则可能是服务器内的消息分发存在问题。以下是有关此问题的几个选项:

**1.检查消息广播逻辑:**检查您的chat_app_function,确保它正确地广播消息到用户的房间。确保它使用sio.emit或类似的方法将消息发送到相应的房间,并且不存在导致消息被跳过的条件。
**2.验证房间成员身份:**请再次确认较旧的页签是否为正确房间的成员。您可以记录特定SID的房间成员身份,以确保它们位于发送消息的房间中。
**3.重连事件处理:**标签页重连时,确保标签页正确的重新建立连接并重新加入房间,需要有重连事件和房间加入的处理逻辑。示例:

socket.on("reconnect", () => {
  // Rejoin the room or perform other necessary actions
});

字符串

**4.考虑实现确认:**在消息发送过程中实现确认,可以帮助您确认客户端是否收到消息,客户端可以确认收到,服务器端可以确认未收到,保证消息传递的可靠性。

这些建议应该能有效地解决这个问题,确保旧的标签页能按预期收到消息。如果这些建议对你的情况有帮助,请告诉我。

nzk0hqpo

nzk0hqpo2#

问题是client_manager丢失了。我不得不将AsyncRedisManager添加到AsyncServer。使用消息代理:实现一个像Redis,RabbitMQ或Kafka这样的消息代理来管理多个worker之间的消息和事件同步。当用户发送消息或事件时,它可以发布到消息代理,所有worker都可以订阅它以接收更新。
换句话说,room1room1对于两个不同的用户可能是不同的。
修复它的代码如下:

manager = socketio.AsyncRedisManager("redis://localhost:6379/0")
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*", client_manager=manager)

字符串
我还需要使用pip3 install aioredis来完成这项工作。

相关问题