服務端主動給客戶端推送消息


在了解這個之前,先要知道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)
            拿着它去解析后面的真實數據(依據一個計算公式)
"""

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM