• 服务端主动给客户端推送消息


    服务端主动给客户端推送消息

    如何实现(目录)
    • 轮询
    • 长轮询
    • websocket

    应用场景:大屏幕实时投票、任务执行的流程...

    饭前甜点

    • ajax操作

      异步提交,局部刷新。用它就可以实现我们上面的轮询/长轮询

      $.ajax({
        url:'',  # 后端服务器地址
        type:'',  # 请求方式
        data:{},  # 发送的数据
        dataType:'JSON',  # 如果django后端是通过HttpResponse返回数据的那么不会自动返序列化,而如果是JsonResponse则会自动转化,该参数可以不指定
        success:function(args){
          # 执行成功之后需要进行的操作  异步回调
        }
      })
      
      return HttpResponse(json.dumps(back_dic))  # 需要dataType参数
      return JsonResponse(back_dic)  # 不需要
      

      补充:templates模版文件夹可以放在全局,也可以在每一个应用下创建该文件夹

      如果全局没有,那么在查找模版的时候就会去应用下查找模版,顺序是按照配置文件中注册了的app的顺序依次查找

    • 队列

      队列:先进先出

      堆栈:先进后出

      import queue
      
      
      q = queue.Queue()  # 创建一个队列
      
      
      q.put('jason')  # 朝队列中丢数据
      q.put('egon')
      
      
      v1 = q.get()  # 获取数据
      v2 = q.get()
      # v3 = q.get()  # 如果没有数据了,get方法默认会一直阻塞
      try:
          v3 = q.get(timeout=3)  # 等3秒 之后还没数据直接报错   queue.Empty
      except queue.Empty as e:
          print(e)
      print(v1,v2)
      # 注意该队列并不会用于实际生产 主要是用来做本地的测试
      # 实际生产建议使用redis、kafka、rebittMQ
      

      基于队列和ajax我们来设想:实现群聊功能

      pending状态

    • 递归

      # python最大递归深度多少呀 997、998、... 官网说是1000
      def func():
        	func()
      func()
      
      # 在js中 根本没有递归的概念 函数内部自己调用自己是可以的 属于正常事件范畴
      function func1(){
        $.ajax({
          url:'',
          type:'get',
          data:{},
          success:function(args){
            func1()
          }
        }) 
      }
      $(function(){  # 等待页面加载完毕之后执行函数内的代码
       	func1()
      })
      
    • modelform

      forms组件的加强版

      自动校验数据、渲染标签、展示错误信息

    服务端朝客户端主动推送消息

    • 轮询

      效率低、基本不用

      让浏览器定时朝后端发送请求(通过ajax向后端偷偷发送数据),比如每隔五秒钟发一次请求,那么你的数据延迟就可能会高达五秒
      
      不足之处
      	数据延迟
        消耗资源过大
        请求次数太多
      
    • 长轮询

      兼容性好

      一般大公司都会考虑使用它

      # 队列+ajax
      服务端给每个客户端建立队列,让浏览器通过ajax朝服务端要数据,去各自的队列中获取
      如果没有数据则会阻塞但是不会一直阻塞,比如阻塞你30秒,还没有数据则返回,然后让客户端浏览器再次发送请求数据的请求
      
      相对于轮询
      	基本是没有消息延迟的
        请求次数降低了很多
        
      # web版本的qq和微信基本上用的都是这么一个逻辑
      

      基于ajax及队列实现长轮询的功能

      """
      1.首页自定义用户唯一表示,给每个用户初始化一个队列
      2.发送按钮绑定点击事件 后端讲数据放入每一个队列中
      3.书写自动获取数据的ajax代码 循环调用
      4.前端获取数据DOM操作渲染页面
      """
      $('#d1').click(function () {
              $.ajax({
                  url:'/send_msg/',
                  type:'post',
                  data:{'content':$('#d2').val()},
                  dataType:'JSON',
                  success:function (args) {
                  }
              })
          });
          function getMsg(){
              $.ajax({
                  url:'/get_msg/',
                  type:'get',
                  data:{'name':'{{ name }}'},  // 只要当前登陆人的队列中的数据
                  {#dataType:'JSON',#}
                  success:function (args) {
                      // 针对返回的消息做相应的处理
                      if(args.status){
                          // 有消息则渲染页面  讲消息全局放到聊天纪录里面
                          // 1 创建标签
                          var pEle = $('<p>');
                          // 2 给标签设置文本内容
                          pEle.text(args.msg);
                          // 3 讲创建好的标签添加到聊天记录div标签内
                          $('#content').append(pEle)
                      }else{
                          // 没有消息 则继续发送
                      }
                      getMsg()  // 循环请求数据
                  }
              })
          }
          $(function () {
              getMsg()  // 等待页面加载完毕自动执行
          })
                
                
      # 后端
      # 全局大字典
      q_dict = {}  # {'唯一表示':队列,....}
      
      
      def ab_bl(request):
          # 获取我们自定义的客户端唯一标识
          name = request.GET.get('name')
          # 给每一个客户端创建一个队列
          q_dict[name] = queue.Queue()
          return render(request,'ab_bl.html',locals())
      
      def send_msg(request):
          if request.method == 'POST':
              # 获取用户发送的消息
              content = request.POST.get('content')
              # 讲该消息传递给所有的队列
              for q in q_dict.values():
                  q.put(content)
              return HttpResponse('OK')
      
      def get_msg(request):
          name = request.GET.get('name')
          # 拿到对应的队列
          q = q_dict.get(name)
          # 讲队列中可能有的数据取出并返回给前端浏览器
      
          # 定义一个字典与ajax进行交互
          back_dic = {'status':True,'msg':''}
          try:
              data = q.get(timeout=10)  # 等10s 没有则直接报错
              back_dic['msg'] = data
          except queue.Empty as e:
              back_dic['status'] = False
          return JsonResponse(back_dic)
          # return HttpResponse(json.dumps(back_dic))
      
    • websocket

      真正的做到服务端发送消息而不再是被动的发送

      目前主流的浏览器都是支持websocket

      """
      HTTP协议  网络协议(不加密传输)
      HTTPS协议 网络协议(加密传输)
      	上面两个协议都是短链接
      
      websocket网络协议  (加密传输)
      	浏览器和服务端创建链接之后 默认不再断开 
      	两端都可以基于该链接收发消息
      	websocket的诞生能够真正做到服务端发送消息而不再是被动的发送
      """
      

      websocket内部原理(了解 面试可以说关键点)

      """
      分成两大部分
      	1.握手环节:验证服务端是否支持websocket协议
      		先连接服务器
      		
      		浏览器产生一个随机字符串 给服务端发送一份(请求头) 自己留一份
      		Sec-WebSocket-Key: ePW8kp1XqLNWbJxE/Q38SA==
      		服务端和客户端都对随机字符串做下面的操作
      		
      		随机字符串 + magic string拼接
      		然后再讲拼接好的结果进行加密处理(sha1/base64)的到密文
      		
      		浏览器自动比对双方产生的密文是否一致,如果一致说明服务端支持websocket
      		如果不一致会报错
      		
      		假设比对上了 建立websocket链接 基于该链接收发消息
      		
      	2.收发数据
      		密文传输 >>> 必然要涉及解密(全球统一)的过程
      		基于网络传输的数据都是二进制格式 对应到我们python中就是bytes类型
      		
      		详见qq群里面的截图
      		数据解密过程
      			1.先读取数据的第二个字节的后7位(payload) 
      			根据7位数据的大小来指定不同的解密流程
      				=127:再往后读取8个字节
      				=126:再往后读取2个字节
      				<=125:不再往后读取
      				
      			除去前面读取的数据之外 再往后读4个字节(masking-key)
      			拿着它去解析后面的真实数据(依据一个计算公式)
  • 相关阅读:
    fckeditor上传问题的解决
    重装系统
    JQuery中文日期控件
    Log4Net使用心得
    not过滤的几种写法
    三级日期选择
    Log4Net本地正常,发布到服务器却不能工作
    工具栏设置大按钮
    Log4Net与Log2Console配合时中文问题的解决
    服务器不能发邮件
  • 原文地址:https://www.cnblogs.com/huangxuanya/p/12487405.html
Copyright © 2020-2023  润新知