iT邦幫忙

0

Django - Websocket 網站實時線上人數

  • 分享至 

  • xImage
  •  

這次要藉由websocket做出網站實時的線上人數,關於django的websocket設定就不贅述了,網路上已經有相當多的資源,就寫一些重點當筆記 ~

一、template

一開始最重要的就是要了解WebSocket支援的四個訊息:onopen,onmessage,onclose和onerror,然後根據你的需求去調用:

  1. onopen:當瀏覽器跟websocket連線成功就可以在console看到"open"訊息,反之,連線失敗則適用於onerror。
    https://ithelp.ithome.com.tw/upload/images/20220207/20129725mlR0omDLpo.png
  2. onmessage:接收處理後端傳來的資料,在這個案例指的是實時的線上人數,如上圖所示目前上線人數為2人{'message':2}。
<body>
    <h1 id="app">{{ text }}</h1>
    <script>
        var socket = new WebSocket('ws://' + window.location.host + '/ws/online_number/');
        socket.onopen = function(e){
              console.log ("open", e);
            }
        socket.onerror = function(e){
          console.log ("error", e)
        }
        socket.onmessage = function(e){
            var data = JSON.parse(e.data);
            var message = data['message'];
            console.log("message",e);
            document.querySelector('#app').innerText = message;
        }
    </script>
</body>

二、consumers.py

我的想法很簡單,只要使用者一進入網站就都放在同一個group裡面,如下圖的灰底部分,反之使用者一離開網站,他的資料就不會再存在於redis,然後只要再去抓取redis裡的數目就會知道實時的人數了,
https://ithelp.ithome.com.tw/upload/images/20220205/20129725SXJArpMWf0.png

  1. 那要怎麼實時的在網站顯示線上使用人數呢?這邊有個重點就是channel_layer.group_send,首先要知道傳送到哪個group(這邊room_group_name是users),再來就是要傳送到前端的資料(這邊一定要寫成字典的形式),type為指定訊息處理的函式(number),這邊就是處理成傳個json,message為從redis得出的人數。

  2. 用redis_connect.zcard得出在group裡的數量即代表線上人數。

小結:connect跟disconnect時都要做差不多的操作來反映出實時的人數。

class NumberOfOnline(AsyncWebsocketConsumer):
    db = Redis(host='127.0.0.1', port=8000, db=0)

    async def connect(self):
        await self.accept()
        self.room_group_name = 'users'
        await self.channel_layer.group_add(self.room_group_name, self.channel_name)
        redis_connect = get_redis_connection('default')
        online_number = str(redis_connect.zcard("asgi:group:users"))
        print('線上人數', online_number)
        await self.channel_layer.group_send(self.room_group_name,{'type':'number', 'message':online_number})

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard('users', self.channel_name)
        user = self.scope['user']
        redis_connect = get_redis_connection('default')
        online_number = str(redis_connect.zcard("asgi:group:users"))
        print('線上人數', online_number)
        await self.channel_layer.group_send(self.room_group_name,{'type':'number', 'message':online_number})

    async def number(self, event):
        message = event['message']
        await self.send(text_data=json.dumps({
            'message': message
        }))

到目前為止只在本機測試,之後部署的話要開始研究asgi server的部分,django目前有提供daphne、Hypercorn、Uvicorn。可能會先試試daphne,但官方文件提供的資訊就只有下圖這樣:
https://ithelp.ithome.com.tw/upload/images/20220208/20129725fmvYW2bYMp.png
感覺會遇到的坑不少...總之就先來try看看吧 ~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言