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

Posted xiongying4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了服务端主动给客户端推送消息相关的知识,希望对你有一定的参考价值。

在了解这个之前,先要知道ajax,队列和递归

ajax操作

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

创建django项目

views

from django.shortcuts import render,HttpResponse
import json
from django.http import JsonResponse
# Create your views here.

# 验证ajax
def ab_dy(request):
    if request.method == post:
       back_dic = {username:tony}
       # return HttpResponse(json.dumps(back_dic))  # 需要dataType参数
       return JsonResponse((back_dic))  # 不需要dataType参数
    return render(request,ab_dy.html)

templates

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax验证</title>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
</head>


<body>
<button id="d1">提交</button>

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

        }
    })

    })

</script>
</body>
</html>

队列

队列:先进先出

堆栈:先进后出

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

递归

# python最大递归深度多少呀 997、998、... 官网说是1000
def func():
      func()
func()

# 在js中 根本没有递归的概念 函数内部自己调用自己是可以的 属于正常事件范畴
function func1(){
  $.ajax({
    url:‘‘,
    type:get,
    data:{},
    success:function(args){
      func1()
    }
  }) 
}
$(function(){  # 等待页面加载完毕之后执行函数内的代码
     func1()
})

轮询

效率低、基本不用

让浏览器定时朝后端发送请求(通过ajax向后端偷偷发送数据),比如每隔五秒钟发一次请求,那么你的数据延迟就可能会高达五秒

不足之处:
数据延迟
消耗资源过大
请求次数太多

长轮询

兼容性好

# 队列+ajax
服务端给每个客户端建立队列,让浏览器通过ajax朝服务端要数据,去各自的队列中获取
如果没有数据则会阻塞但是不会一直阻塞,比如阻塞你30秒,还没有数据则返回,然后让客户端浏览器再次发送请求数据的请求

相对于轮询
    基本是没有消息延迟的
    请求次数降低了很多
  
# web版本的qq和微信基本上用的都是这么一个逻辑

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

1.首页自定义用户唯一表示,给每个用户初始化一个队列
2.发送按钮绑定点击事件 后端讲数据放入每一个队列中
3.书写自动获取数据的ajax代码 循环调用
4.前端获取数据DOM操作渲染页面

views

#全局大字典
q_dict = {}  # {‘唯一标识‘:队列...}

def ab_b1(request):
    # 获取自定义的客户端唯一标识
    name = request.request.GET.get(name)
    # 给每一个客户端创建一个队列
    q_dict[name] = queue.Queue()
    return render(request,ab_b1.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)

templates

$(#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()  // 等待页面加载完毕自动执行
    })

websocket

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

"""
HTTP协议  网络协议(不加密传输)
HTTPS协议 网络协议(加密传输)
    上面两个协议都是短链接

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

websocket内部原理

"""
分成两大部分
    1.握手环节:验证服务端是否支持websocket协议
        先连接服务器
        
        浏览器产生一个随机字符串 给服务端发送一份(请求头) 自己留一份
        Sec-WebSocket-Key: ePW8kp1XqLNWbJxE/Q38SA==
        服务端和客户端都对随机字符串做下面的操作
        
        随机字符串 + magic string拼接
        然后再讲拼接好的结果进行加密处理(sha1/base64)的到密文
        
        浏览器自动比对双方产生的密文是否一致,如果一致说明服务端支持websocket
        如果不一致会报错
        
        假设比对上了 建立websocket链接 基于该链接收发消息
        
    2.收发数据
        密文传输 >>> 必然要涉及解密(全球统一)的过程
        基于网络传输的数据都是二进制格式 对应到我们python中就是bytes类型
        
        数据解密过程
            1.先读取数据的第二个字节的后7位(payload) 
            根据7位数据的大小来指定不同的解密流程
                =127:再往后读取8个字节
                =126:再往后读取2个字节
                <=125:不再往后读取
                
            除去前面读取的数据之外 再往后读4个字节(masking-key)
            拿着它去解析后面的真实数据(依据一个计算公式)
"""

技术图片

 

以上是关于服务端主动给客户端推送消息的主要内容,如果未能解决你的问题,请参考以下文章

怎么实现服务器给android客户端主动推送消息

java中使用websocket推送消息服务器端怎么才能主动推送

webSocket--服务器将数据主动推送给客户端

如何在php后端及时推送消息给客户端

一文了解服务端推送(含JS代码示例)

python web服务端主动推送消息到浏览器页面的具体实现代码