Django+vue实现websocket通信

一、为什么需要websocket?:
前端和后端的交互模式最常见的就是前端发数据请求,从后端拿到数据后展示到页面中。如果前端不做操作,后端不能主动向前端推送数据,这也是http协议的缺陷。

因此,一种新的通信协议应运而生—websocket,他最大的特点就是服务端可以主动向客户端推送消息,客户端也可以主动向服务端发送消息,实现了真正的平等。
  在这里插入图片描述
websocket其他特点如下:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

二、vue部分(客户端):
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);
    }
  },

三、django部分(服务端):
Django通过dwebsocket实现websocket通信:
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)

参考:
python websocket Django 实时消息推送
封装websocket请求-----vue项目实战
Django通过dwebsocket实现websocket
官方链接

猜你喜欢

转载自blog.csdn.net/qq_34663267/article/details/108404816