Django+vue realizes websocket communication

1. Why do we need websocket? : The
most common interaction mode between the front-end and the back-end is that the front-end sends data requests and displays the data on the page after getting the data from the back-end. If the front end does not operate, the back end cannot actively push data to the front end, which is also a defect of the http protocol.

Therefore, a new communication protocol came into being—websocket. Its biggest feature is that the server can actively push messages to the client, and the client can also actively send messages to the server, realizing true equality.
  Insert picture description here
Other features of websocket are as follows:

(1) Based on the TCP protocol, the server-side implementation is relatively easy.

(2) It has good compatibility with HTTP protocol. The default ports are also 80 and 443, and the HTTP protocol is used in the handshake phase, so it is not easy to block during the handshake and can pass through various HTTP proxy servers.

(3) The data format is relatively lightweight, the performance overhead is small, and the communication is efficient.

(4) You can send text or binary data.

(5) There is no homology restriction, and the client can communicate with any server.

(6) The protocol identifier is ws (if encrypted, it is wss), and the server website is the URL.

2.
Vue part (client side): api.js:

export const getWebSocket = () => {
    
    
  let protocol = document.location.protocol === 'https:' ? 'wss://' : 'ws://'
  let url = protocol + document.location.host + '/nms/ws/'
  let ws = new WebSocket(url)
  ws.onopen = onOpen
  ws.onclose = onClose
  return ws
}

home.vue

...
...
...
  mounted: function() {
    
    
    this.initWebSocket()
  },
  ...
  ...
  ...
  

```javascript
  methods: {
    
    
    // ws消息处理
    initWebSocket: function () {
    
    
      this.ws = api.getWebSocket();
      this.ws.onopen = onOpen
      this.ws.onmessage  = this.onMessage;
      this.ws.onerror = this.websocketonerror;
      this.ws.onclose = this.websocketclose;
    },
    websocketonerror(){
    
    //连接建立失败重连
      this.initWebSocket();
    },
    onMessage(evt) {
    
    
      console.log(evt.data);
      let data = JSON.parse(evt.data);
      let status = "";
      // 根据需求做相应的处理
      try {
    
    
        switch (data.eventid) {
    
    
          case "aaa":
            // 抓包开始成功
            ...
            ...
            ...
            break;
          case "bbb":
            // 抓包开始失败
            ...
            ...
            ...
            break;
          ...
          ...
          ...  
          default:
            break;
        }
      } catch (err) {
    
    
        console.warn(err);
      }
    },
    websocketclose(e){
    
      //关闭
      console.log('断开连接',e);
    }
  },

3. Django part (server side):
Django realizes websocket communication through dwebsocket:
view.py

from django.shortcuts import render
import logging
import json
import threading
from dwebsocket.decorators import accept_websocket
import os
from nms_server.utils.myglobal import *
from nms_server.dao.diagnosis import add_capture_file, updata_capture_file
from nms_server.dao.redis.device import get_device_user_moid
from nms_server.rmq import RMQConsumerThread
from django.conf import settings

logger = logging.getLogger('nms.'+__name__)

# 存储连接websocket的用户

# 消费者创建标识
consumer_flag = True


@accept_websocket
def websocket_link(request):
    global consumer_flag
    # '连接websocket'
    # 获取连接
    if request.is_websocket:
        lock = threading.RLock()#rlock线程锁
        try:
            lock.acquire()#抢占资源
            s = {
    
    }
            if consumer_flag:
                try:
                    logger.info('init nms_webserver_consumer: %s' %
                                os.getpid())
                    RMQConsumerThread(
                        name='nms_webserver_consumer_{}'.format(os.getpid()),
                        amqp_url=settings.AMQP_URL,
                        exchange='nms.webserver.ex',
                        queue='nms.webserver.q.{}'.format(os.getpid()),
                        routing_key='nms.webserver.k',
                        exchange_type='topic'
                    ).start()
                    consumer_flag = False
                except Exception as e:
                    logger.error(e)
            user = getattr(request, 'sso_user', None)
            user_moid = ''
            if user is not None: 
                user_moid = user['data']['moid']
            else:
                logger.error('sso_user in None')
                raise ValueError
            
            clients = get_clients()
            #  因为同一个账号打开多个页面连接信息是不同的
            if clients.get(user_moid) != None:
                # 连接信息  键 连接名  值:连接保存
                s[str(request.websocket)] = request.websocket
                # 已存在的连接信息继续增加
                clients[user_moid].update(s)
            else:
                #  连接信息  键 连接名  值:连接保存
                s[str(request.websocket)] = request.websocket
                # 新增 用户  连接信息
                clients[user_moid] = s

            set_clients(clients)
            logger.info('pid:%d ,client: %s',os.getpid(),clients)
            # 监听接收客户端发送的消息 或者 客户端断开连接
            for message in request.websocket:
                if not message:
                    break
                else:
                    client_msg_handler(user_moid,message)
        finally:
                logger.info('close client connect,user_moid:%s,request.websocket:%s',user_moid,str(request.websocket))
                # 通过用户名找到 连接信息 再通过 连接信息 k 找到 v (k就是连接信息)
                clients = get_clients()
                clients.get(user_moid).pop(str(request.websocket))
                if not clients.get(user_moid):
                    clients.pop(user_moid)
                set_clients(clients)
                logger.info('client: %s',clients)
                #释放锁
                lock.release()

# 客户端消息处理
def client_msg_handler(user_moid,msg):
    logger.info('[client_msg_handler] msg:%s' ,msg.decode('utf-8'))

    # test代码
    # import time
    # data = {
    
    
    #     'event':'ack',
    #     'text':'hello world'
    # }
    # for i in range(5):
    #     data['id'] = i
    #     send_msg_to_client(user_moid,data)
    #     time.sleep(1)
    pass

 # 发送消息
def websocketMsg(client, msg):
    # 因为一个账号会有多个页面打开 所以连接信息需要遍历
    for cli in client:
        b1 = json.dumps(msg).encode('utf-8')
        client[cli].send(b1)

'''
@description: 服务端发送消息
@user_moid {str}  用户moid
@msg {json}  消息
@return:        
'''
def send_msg_to_client(data):
    clients = get_clients()
    logger.info('pid:%d, send_msg_to_client(data): %s',os.getpid(),data)
    logger.info('pid:%d ,client: %s',os.getpid(),clients)
    try:
        if data['user_moid'] == '':
            data['user_moid'] = get_device_user_moid(data['devid'],data['devtype'])

        user_moid = data['user_moid'] 
        if clients[user_moid]:
            if data['eventid'] == 'EV_PACKETCAPTURE_STOP_ACK':
                # 保存抓包文件到数据库
                file_name = data["url"].split("/")[-1]
                create_time = data['rpttime'].replace("/", "-").split(':',1)
                create_time = create_time[0] + " " + create_time[1]
                add_capture_file(data['user_moid'],
                                    data['devid'],
                                    file_name,
                                    data.get('size',0),
                                    create_time)

            if data['eventid'] == 'EV_PACKETCAPTURE_UPLOAD_PROGRESS_NTF':
                # 更新终端抓包文件信息
                file_name = data["url"].split("/")[-1]
                if 'size' in data:
                    updata_capture_file(data['user_moid'],
                                        data['devid'],
                                        file_name,
                                        data['size'])

            websocketMsg(clients[user_moid],data)
    except BaseException as e:
        logger.error(e)

Reference:
python websocket Django real-time message push
package websocket request-----vue project actual combat
Django realizes websocket official link through dwebsocket

Guess you like

Origin blog.csdn.net/qq_34663267/article/details/108404816