代碼發布項目(一)——實現服務端主動給客戶端推送消息(websocket)


截至目前為止,我們所接觸到的項目內部都是基於HTTP協議實現通信的:http協議是無鏈接無狀態,客戶端發送請求,服務端返回響應,服務端不會自動朝客戶端發送消息。

有三種方式實現服務端主動向客戶端推送消息:

1.輪詢
2.長輪詢
3.websocket

輪詢

效率低、基本不用

讓瀏覽器定時朝后端發送請求(通過ajax向后端偷偷發送數據),比如每隔五秒鍾發一次請求,那么你的數據延遲就可能會高達五秒

不足之處
  數據延遲
  消耗資源過大
  請求次數太多

長輪詢

兼容性好,一般大公司都會考慮使用它

# 隊列+ajax
服務端給每個客戶端建立隊列,讓瀏覽器通過ajax朝服務端要數據,去各自的隊列中獲取
如果沒有數據則會阻塞但是不會一直阻塞,比如阻塞你30秒,還沒有數據則返回,然后讓客戶端瀏覽器再次發送請求數據的請求。
讓瀏覽器內部偷偷的朝服務端獲取數據,客戶端第一次來的時候會給每一個客戶端創建一個獨有的隊列,之后客戶端請求數據都是從自己對應的隊列中索要,
由於隊列沒有數據的時候,get方法會阻塞一旦有數據又會立刻運行,所以我們利用timeout參數加異常捕獲的方式來做到基本零延遲
相對於輪詢 基本是沒有消息延遲的 請求次數降低了很多
# web版本的qq和微信基本上用的都是這么一個邏輯

基於ajax及隊列實現的長輪詢的功能(django簡易版的聊天室)

"""
1.首頁自定義用戶唯一表示,給每個用戶初始化一個隊列
2.發送按鈕綁定點擊事件 后端講數據放入每一個隊列中
3.書寫自動獲取數據的ajax代碼 循環調用
4.前端獲取數據DOM操作渲染頁面
"""

urls.py

#基於ajax+隊列實現長輪詢,聊天頁面
url(r'^ab_bl/', views.ab_bl),
#前端給后端發送信息
url(r'^send_msg/', views.send_msg),
#展示前端的信息
url(r'^get_msg/', views.get_msg),

ab_bl.html

<body>
<h1>{{ name }}聊天室</h1>
<p>
  <input type="text" name="content" id="d2">
  <button id="d1">發送</button>
</p>
<h1>聊天記錄</h1>
<div id="content"></div>

<script>
  //點擊發送觸發ajax
  $('#d1').click(function () {
      $.ajax({
          url:'/send_msg/',  //消息發送地址,后端
          type:'post',
          data:{'content':$('#d2').val()},  //傳遞給后端的信息
          success:function (data) {  //后端返回給前端的消息

          }
      })
  });

  function getMsg(){
        $.ajax({
            url:'/get_msg/',
            type:'get',
            data:{'name':'{{ name }}'},  // 只要當前登陸人的隊列中的數據
            success:function (args) {
                // 針對返回的消息做相應的處理
                if(args.status){
                    // 有消息則渲染頁面  講消息全局放到聊天紀錄里面
                    // 1 創建標簽
                    var pEle = $('<p>');
                    // 2 給標簽設置文本內容
                    pEle.text(args.msg);
                    // 3 講創建好的標簽添加到聊天記錄div標簽內
                    $('#content').append(pEle)
                }else{
                    // 沒有消息 則繼續發送
                }
                getMsg()  // 循環請求數據
            }

        })
    }
  $(function () {
      getMsg()  //頁面加載完畢自動執行
  })
</script>
</body>

views.py

from django.shortcuts import render,HttpResponse
import queue
from django.http import JsonResponse
# 全局大字典
q_dict = {}  # {'唯一表示':隊列,....}

def ab_bl(request):
    #從路徑傳參name,用於做每個用戶的標識
    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':
        #獲取用戶發送的消息:ajax中data傳遞的數據
        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)

websocket

真正的做到服務端發送消息而不再是被動的發送

目前主流的瀏覽器都是支持websocket

HTTP協議  網絡協議(不加密傳輸)
HTTPS協議 網絡協議(加密傳輸)
    上面兩個協議都是短鏈接

websocket網絡協議  (加密傳輸)
    瀏覽器和服務端創建鏈接之后 默認不再斷開 
    兩端都可以基於該鏈接收發消息
    websocket的誕生能夠真正做到服務端發送消息而不再是被動的發送

websocket內部原理

分成兩大部分
    1.握手環節:驗證服務端是否支持websocket協議
        第一次訪問服務端的時候(基於http協議) 瀏覽器產生一個隨機字符串放在請求頭中給服務端發送一份,自己留一份
        Sec-WebSocket-Key: ePW8kp1XqLNWbJxE/Q38SA==
        服務端和客戶端都對隨機字符串做下面的操作
        
        隨機字符串 + magic string拼接
        然后再講拼接好的結果進行加密處理(sha1/base64)的到密文
        
     服務端將產生的密文通過響應頭再次發送給客戶端瀏覽器 瀏覽器自動比對雙方產生的密文是否一致,如果一致說明服務端支持websocket 如果不一致會報錯 假設比對上了 建立websocket鏈接 基於該鏈接收發消息
2.收發數據 密文傳輸 >>> 必然要涉及解密(全球統一)的過程 基於網絡傳輸的數據都是二進制格式 對應到我們python中就是bytes類型 數據解密過程 1.對收到的消息,先讀取數據的第2個字節的后7位(payload)字節 根據7位數據的大小來指定不同的解密流程 =127:再往后讀取8個字節 =126:再往后讀取2個字節 <=125:不再往后讀取 除去前面讀取的數據之外 再往后讀4個字節(masking-key) 拿着它去解析后面的真實數據(依據一個計算公式)

代碼驗證

后端代碼無需掌握,前端的就行

<!--前端只需要寫一行代碼就可以了-->
<script>
    var ws = new WebSocket('ws://127.0.0.1:22/')
</script>

<!--通過ws對象點send方法即可實現websocket的數據交互-->

 


免責聲明!

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



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