websocket簡單使用


websocket

  • 使用webscoket實現類似web 微信的一個即時通訊工具
  • 流程
    1. 做前端
    2. 建立webserver django / flask
    3. 制作聊天功能

1. 輪詢和長鏈接

1. 輪詢

  • 輪詢:只是查詢沒有超時時間
  • 不能保證數據的實時性
# A、B client:無限循環和服務器對話,有 xx 消息嗎?
  • 長輪詢:默認有超時時間
# A、B client:client 發起請求至 server,等待15s(默認http超時時間) --> 等待消息時間
# -->主動斷開連接
# -->收到消息主動返回

2. 長鏈接

  • 短連接:通訊雙方有數據交互時,就建立一個連接,數據發送完成后,則斷開此連接,即每次連接只完成一項業務的發送。
  • 長連接,指在一個連接上可以連續發送多個數據包,在連接保持期間,如果沒有數據包發送,需要雙方發鏈路檢測包。

長連接特性:

  1. A、B client --> server 建立連接並保持連接不斷開
  2. A to B --> server 消息轉發 -->B 建立連接的情況下,可以及時准確收到消息
  3. 客戶端和服務器保持永久性連接
  4. 除非有一方主動發起斷開
  5. 消息轉發

2. Websocket

  • 實現的組件:werkzeug、gevent-websocket

1. 示例

  • 長連接
  • web + socket
  • Flask + Websocket 模塊 + gevent-websocket
# 下載 gevent-websocket,Websocket
# 請求處理 WSGI 處理 HTTP 請求,WebSocketHandler處理socket請求
# 使用 WSGIServer 替換flask的 Werkzueg
# 語法提示
from flask import Flask
from geventwebsocket.hander import WebSocketHandler
from geventwebsocket.server import WSGIServer
from geventwebsocket.websocket import WebSocket

app = Flask(__name__)

@app.route('/ws')
def ichat():
    print(request.environ)
    ws_socket = request.environ.get('wsgi.websocket') # type:WebSocket
    try:
        while True:
            msg = ws_socket.receive()
            print(msg)
            ws_socket.send(b'xxx')
    except:pass
    # return '200 ok!'


if __name__ == '__main__':
    # handler_class=WSGIhandler(not sure),只支持http請求
    http_server = WSGIServer(('0.0.0.0', 9527), app, handler_class=WebSocketHandler)
    http_server.server_forever()

2. websocket的狀態碼

  • 0:連接創建失敗,
  • 1:當前link激活,處於可用狀態
  • 2:客戶端主動斷開連接,看不到其狀態碼
  • 3:服務器主動發起斷開
<script type='application/javascript'>
	var ws = new WebSocket('ws://127.0.0.1:5000/chat');
    ws.onmessage = function (messageEvent) {
        console.log(messageEvent.data);

        var ptag = document.createElement('p');
        ptag.innerText = messageEvent.data;
        document.getElementById('content_list').appendChild(ptag);
    };
    function send_message() {
        var msg = document.getElementById('content').value;
        ws.send(msg);
    }
</script>
// ws.close

3. websocket

1. 單聊示例

  1. 群聊時使用 socket_list = [],記錄每個連接用戶socket_obj
  2. 單聊時使用 socket_dict = {},記錄sender 、reciver 和 msg
socket_list = []
@app.route('/chat/<username>')
def chat(username):
    # print(request.environ)
    websocket_obj = request.environ.get('wsgi.websocket')  # type:WebSocket
    websocket_dict[username] = websocket_obj

    while True:
        msg = websocket_obj.receive()

        msg_dict = json.loads(msg)
        receiver = msg_dict.get('receiver')
        try:
            receiver_socket = websocket_dict.get(receiver)

            receiver_socket.send(msg)
        except:
            msg = {'sender': '系統',
                   'receiver': username,
                   'data':'對方不在線',
            }
            websocket_obj.send(json.dumps(msg))


@app.route('/ws')
def ws():
    return render_template('ptop.html')
  • ptop.html中的 js
<script type="application/javascript">
    var ws;
    function send_message() {
        var msg = {
            sender:document.getElementById('username').value,
            receiver:document.getElementById('receiver').value,
            data:document.getElementById('content').value,
        };

        var data = JSON.stringify(msg);
        ws.send(data);

        var ptag = document.createElement('p');
        ptag.innerText = msg.data + ':' + msg.sender;
        ptag.style.cssText = "text-align:right";
        document.getElementById('content_list').appendChild(ptag);
    }

    function login() {
        var username = document.getElementById('username').value;
        ws = new WebSocket('ws://127.0.0.1:5000/chat/' + username);
        ws.onmessage = function (messageEvent) {
            // 收到信息后先反序列化,在創建 p 標簽並加入到div中
            var msg = JSON.parse(messageEvent.data);
            var ptag = document.createElement('p');
            ptag.innerText = msg.sender + ':' + msg.data;
            document.getElementById('content_list').appendChild(ptag);
        };
    }
</script>

2. 基於websocket實現群聊

  1. 建立websocket 服務 + Flask web 框架 + Gevent-WebSocket
  2. requst.environ.get('wsgi.websocket')獲取鏈接,並保存到服務器中
  3. 基於長連接socket 接收用戶傳遞的消息
  4. 將消息轉發給其他用戶

3. 基於javascirpt 實現websocket客戶端

  1. 服務器保存的連接方式變化,以dict形式儲存
    • 存儲結構:{uid: websocket連接, user1:websocket}
  2. 消息發送時,receiver, data = {'sender':發送方, 'receiver':接收發, data:數據}
    • 從data中找到接收方的key
    • 去存儲結構中找到 key 對應的websocket連接
  3. websocket.send(data). socket傳輸, bytes類型
  4. js 中常用的事件
var ws = new WebSocket('ws://ip:port/路徑')
// ws.onmessage 當ws客戶端收到消息時執行回調函數
// ws.onopen 當ws客戶端建立完成連接時, status == 1 時執行
// ws.onclose 當ws客戶端關閉中后關閉,執行的回調函數,status 2 或 3
// ws.onerror 當ws客戶端出現錯誤時
ws.onmessage = func(messageEvent){
    ...
}

4. 示例

import json

from flask import Flask, request
from geventwebsocket.handler import WebSocketHandler
from geventwebsocket.server import WSGIServer
from geventwebsocket.websocket import WebSocket

ws = Flask(__name__)
web_socket = {}

@ws.route('/app/<user_id>')
def app(user_id):
    app_socket = request.environ.get('wsgi.websocket')  # type:WebSocket
    web_socket[user_id] = app_socket
    print('建立app_socket連接。。。', app_socket, user_id)
    while True:
        try:
            # 收發數據
            msg = app_socket.receive()
            msg_info = json.loads(msg)
            receiver = msg_info.get('to_user')
            receiver_socket = web_socket.get(receiver)
            try:
            	receiver_socket.send(msg)
            except:
                web_socket.pop(receiver)
        except:
            pass

@ws.route('/toy/<toy_id>')
def toy(toy_id):
    toy_socket = request.environ.get('wsgi.websocket')  # type:WebSocket
    web_socket[toy_id] = toy_socket
    print('保持toy_socket連接。。。', toy_socket, toy_id)
    while True:
        try:
            msg = toy_socket.receive()
            msg_info = json.loads(msg)
            receiver = msg_info.get('to_user')
            receiver_socket = web_socket.get(receiver)
            receiver_socket.send(msg)
        except:
            pass


if __name__ == '__main__':
    http_server = WSGIServer(('0.0.0.0', 9528), ws, handler_class=WebSocketHandler)
    http_server.serve_forever()


免責聲明!

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



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