_坐看云起时_ 2024-03-01 11:21 采纳率: 100%
浏览 128
已结题

websocket在刷新网页后断开,且报错:took too long to shut down and was killed.

情景:
django开发,已经部署网站到阿里云服务器,使用daphne监听,用websocket通信,使用 daphne -b 0.0.0.0 -p 8000 djangoProject.asgi:application启动监听后,打开网页,网站可以正常运行,但是当刷新网页或者再次重复打开这个网页,websocket就会断开,在终端报出这样的错误:
157.0.207.36:9342 - - [01/Mar/2024:03:06:43] "WSDISCONNECT /room/hony" - -
157.0.207.36:13765 - - [01/Mar/2024:03:06:44] "WSCONNECTING /room/hony" - -
157.0.207.36:13765 - - [01/Mar/2024:03:06:49] "WSDISCONNECT /room/hony" - -
2024-03-01 03:06:53,756 WARNING Application instance <Task pending name='Task-1' coro=<ProtocolTypeRouter.__call__() running at /envs/MCSenv/lib/python3.9/site-packages/channels/routing.py:71> wait_for=<Future pending cb=[_chain_future.._call_check_cancel() at /usr/local/lib/python3.9/asyncio/futures.py:384, <TaskWakeupMethWrapper object at 0x7f7a1fab0e50>()]>> for connection <WebSocketProtocol client=['157.0.207.36', 9342] path=b'/room/hony'> took too long to shut down and was killed.

websocket的错误码是1006,reason为空

代码:
js文件:


 var socket = new WebSocket("ws:39.101.76.7:8000/room/hony");

socket.onopen = function(event) {
    console.log('WebSocket连接已建立');
    socket.send('start_query');
    // socket.send(JSON.stringify({
    //     'type': 'join_group',
    //     'group_name': 'your_group_name',
    // }));
};


socket.onmessage = function(event) {
    // const data = JSON.parse(event.data);
     var parsedData = JSON.parse(event.data);

     parsedData.locations.forEach(function(location) {
           markLocation(location.latitude, location.longitude, location.signalStrength);
    });

    //
    //     // 标记为已接收
    // socket.send('received');
};



socket.onclose = function(e) {
  console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean);
  console.log(e);

};


consumers.py:

class MyConsumer(WebsocketConsumer):
    def connect(self):
       self.accept()
       self.channel_layer.group_add('your_group_name', self.channel_name)
       print('WebSocket连接已建立')

    def disconnect(self, close_code):
        self.channel_layer.group_discard('your_group_name', self.channel_name)
        print('WebSocket连接已关闭')

    def receive(self, text_data):
        # 接收到来自WebSocket的数据
        print("接收到consumer2" + text_data)
        if text_data == 'start_query':
            locations = LocationData.objects.all()
            data = [
                {
                    'latitude': loc.latitude,
                    'longitude': loc.longitude,
                    'signalStrength': loc.signal_strength
                }
                for loc in locations
            ]
            locations.update(is_ask=True)
            self.send(text_data=json.dumps({'locations': data}))
            while True:
                locations = LocationData.objects.filter(is_ask=False)  # 获取未被处理的位置数据
                data = [
                    {
                        'latitude': loc.latitude,
                        'longitude': loc.longitude,
                        'signalStrength': loc.signal_strength
                    }
                    for loc in locations
                ]
                locations.update(is_ask=True)
                self.send(text_data=json.dumps({'locations': data}))
                time.sleep(30)  # 30秒后再次查询

    def send_data(self, event):
        print("hjcbjdbsjcbsdbch")
        # 从Consumer2接收到数据并发送给Web客户端的JavaScript文件
        data = event['data']
        print("接收到consumer2" + data)
        self.send(data)


请问这是什么原因,如何解决

  • 写回答

1条回答 默认 最新

  • 檀越@新空间 2024-03-01 11:31
    关注

    _坐看云起时_ 上午好☀️☀️☀️️
    本答案参考通义千问

    WebSocket在刷新网页后断开的问题 可能是由于以下原因导致的:

    1. 服务器端超时设置

      • Django的Daphne默认情况下可能会对长时间没有活动的连接进行清理,如果连接保持时间过长,可能会触发took too long to shut down and was killed的错误。
    2. 浏览器限制

      • 浏览器可能有自身的限制,比如长时间未交互会自动断开连接。
    3. 代码逻辑问题

      • receive方法中的无限循环可能导致连接占用过多资源,影响响应速度。

    为了解决这个问题,你可以采取以下措施:

    解决方案:

    1. 调整服务器端超时设置

      • consumers.py中,找到Daphne的ProtocolTypeRouter类,可能需要调整max_age参数来延长连接的存活时间。例如:
      from channels.routing import ProtocolTypeRouter, URLRouter
      from django.core.asgi import get_asgi_application
      
      application = ProtocolTypeRouter(
          {
              "http": get_asgi_application(),
              "websocket": URLRouter([
                  # ...其他路由配置...
                  # 调整WebSocket的超时时间(以秒为单位)
                  path("ws/room/<str:room_name>", MyConsumer.as_asgi(), options={"max_age": 60 * 60}),  # 60分钟
              ]),
          }
      )
      
    2. 优化无限循环

      • 可能需要移除while True循环,或者添加一个检查条件来确保循环不会无限期运行。例如:
      def receive(self, text_data):
          # ...
          if text_data == 'start_query':
              # 使用信号系统或者定时任务来定期查询数据,而不是在循环中
              from django.db.models import Q
              locations = LocationData.objects.filter(Q(is_ask=False) & Q(last_poll__lte=timezone.now() - timedelta(seconds=30)))
              # ...处理数据和发送
              locations.update(is_ask=True)
              # 每次查询后设置下次查询的时间点,而不是无限循环
              self.next_poll_time = timezone.now() + timedelta(seconds=30)
          # ...
      

      然后在send_data方法中检查是否到了下一次查询的时间:

      def send_data(self, event):
          if self.next_poll_time and timezone.now() >= self.next_poll_time:
              # 进行下一次查询
              self.receive('start_query')
              self.next_poll_time = None  # 或者重新计算下次查询时间
      
    3. 客户端行为

      • 如果浏览器限制是问题,可以考虑在前端实现心跳机制,定期向服务器发送ping消息,以保持连接活跃。

    通过这些调整,应该可以减少WebSocket连接因超时而被关闭的问题。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 3月9日
  • 已采纳回答 3月1日
  • 创建了问题 3月1日