socketserver模塊使用 & websocket


socketserver:

socketserver可用於實現並發通信。

socketserver 模塊簡化了編寫網絡服務程序的任務;同時 SocketServer 模塊也是 Python標准庫中很多服務器框架的基礎。
socketserver 模塊可以簡化網絡服務器的編寫。Python把網絡服務抽象成兩個主要的類,一個是 Server 類,用於處理連接相關的網絡操作,另外一個則是 RequestHandler 類,用於處理數據相關的操作;並且提供了兩個Mixin類,用於擴展 Server,實現多進程或多線程。

Server 類:
它包含了種五種server類,BaseServer(不直接對外服務)。TCPServer使用TCP協議,UDPServer使用UDP協議,還有兩個不常使用的,
即UnixStreamServer和UnixDatagramServer,這兩個類僅僅在unix環境下有用(AF_unix)。

RequestHandler類:
所有requestHandler都繼承BaseRequestHandler基類。

注: 全雙工管道通信:既可以 收,也可以 發

單工、半雙工和全雙工的區別: https://blog.csdn.net/starstar1992/article/details/53032409

 

socketserver 的使用方法:

import socketserver

"""
socketserver: 基於多線程實現的並發通信
sockerserver 使用方法(固定套路):
1. 定義功能類
    class MyServer(socketserver.BaseRequestHandler):  
        def handler(self):  
            pass

2. server = socketserver.threadingTCPServer(("127.0.0.1",8800),MyServer) 

3. server.server_forerver()  
"""

class MyServer(socketserver.BaseRequestHandler):  # 必須要繼承 socketserver.BaseRequestHandler 這個類
    
    def handler(self):  # 必須要有 handler() 這個方法
        """
        handler() 方法里面要放並發的業務邏輯
        該方法下的 self.request 也是固定寫法,是一個套接字對象,即相當於 以前 socket 時的 conn
        """
        # 寫自己的業務邏輯
        pass


# 通過 socketserver 引一個要 並發的類
server = socketserver.ThreadingTCPServer(("127.0.0.1",8800),MyServer)   # 第一個參數:IP和端口,第二個參數:要實例化的 功能類;threadingTCPServer 這個類是通過 多線程 幫我們實現的並發;用的是 TCP 協議
# server = socketserver.ForkingTCPServer(("127.0.0.1",8800),MyServer)  # 多進程 TCP 通信
server.server_forerver()

 

websocket:

websocket 其實就是 web socket,它也是一種協議

http 的問題:
    1. http 是一個協議
        - 數據格式
        - 一次請求和響應之后斷開連接(無狀態、短連接)
    2. 服務端不可以向客戶端主動推送消息(因為不知道客戶端的IP端口)
    3. 服務端只能做出響應
    4. 為了偽造服務端向客戶端主動推送消息的效果,我們使用:輪詢和長輪詢

websocket 是一種新的協議: 1. 連接時需要握手;2.發送數據進行加密;3.連接之后不斷開;  websocket 解決了 服務端能夠真正向客戶端推送消息;缺點:兼容性 
    - 數據格式:
        - 連接請求: http協議
        - 收發請求: websocket協議
    - 不斷開連接
    
基於 flask的websocket示例:
# 安裝:
pip install gevent-websocket

支持 websocket 的框架:
  所有框架都支持,但是,
  flask : gevent-websocket
  django:channel
  tornado 框架自帶 websocket

應用場景:實時響應

 

基於 flask 和 websocket 實現一個在線投票功能:

app.py

from flask import Flask,render_template,request
import json

# 使用 websocket 時 需要導入下面的兩個模塊
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer


# 發送 websocket 請求得通過 js 來實現

app = Flask(__name__)

USERS = {
    '1':{'name':'鋼彈','count':0},
    '2':{'name':'鐵錘','count':0},
    '3':{'name':'貝貝','count':100},
}


# http://127.0.0.1:5000/index  # 瀏覽器在渲染 index.html 時,在執行 var ws = new WebSocket('ws://192.168.13.253:5000/message') 這句js代碼時,客戶端就會和服務端建立一個 websocket 的連接
@app.route('/index')
def index():
    return render_template('index.html',users=USERS)

# http://127.0.0.1:5000/message
WEBSOCKET_LIST = []  # 用於保存所有的 websocket 連接;可理解為所有的客戶端

@app.route('/message')
def message():
    ws = request.environ.get('wsgi.websocket')  # 如果不是 websocket 協議的請求,request.environ.get('wsgi.websocket') 的值是 None;如果是 websocket 請求, ws 將是一個 websocket 對象
    if not ws:
        print('http')
        return '您使用的是Http協議'
    WEBSOCKET_LIST.append(ws)  # 把當前的 ws 連接添加到 WEBSOCKET_LIST 中
    while True:
        cid = ws.receive()  # 接收投票的 cid; ws.receive() :接收客戶端發過來的 websocket協議的 數據
        if not cid: # 如果客戶端關閉連接 ws.receive() 接收到的將會是 None
            WEBSOCKET_LIST.remove(ws)
            ws.close()  # 后台的 ws 也關閉
            break
            
        old = USERS[cid]['count']
        new = old + 1
        USERS[cid]['count'] = new
        
        for client in WEBSOCKET_LIST:
            client.send(json.dumps({'cid':cid,'count':new}))  # 給前端返回一個字典

# 服務端通過 websocket 協議就可以向客戶端主動推送消息;這是由於 客戶端與服務端的連接沒有斷開; 需要事先在客戶端的瀏覽器上 new 一個 WebSocket 的對象 (WebSocket 支持H5等,但低版本的瀏覽器不支持)

if __name__ == '__main__':
    http_server = WSGIServer(('0.0.0.0', 5000), app, handler_class=WebSocketHandler)  # 如果是 http 協議的請求,就交給 app 去處理;如果是 websocket 協議的請求,就交給 WebSocketHandler 去處理。 # app 的 werkzeug 只能處理 http 請求
    http_server.serve_forever()

 

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <h1>丑男投票系統</h1>
    <ul>
        {% for k,v in users.items() %}
            <li onclick="vote({{k}})" id="id_{{k}}">{{v.name}}<span>{{v.count}}</span></li>
        {% endfor %}
    </ul>

    <script src="{{ url_for('static',filename='jquery-3.3.1.min.js')}}"></script>
    <script>
        var ws = new WebSocket('ws://192.168.13.253:5000/message')  // 實例化一個WebSocket 對象: 用於向 192.168.13.253:5000/message 這個url 發送 websocket 協議的請求;該連接不會斷開 
        // 前端通過 ws.send("你好")  來發送 websocket協議的數據
        
        ws.onmessage = function (event) {  // 服務端返回 ws 數據的時候, ws.onmessage() 自動觸發
            /* 服務器端向客戶端發送數據時,自動執行 */
            // {'cid':cid,'count':new}
            var response = JSON.parse(event.data);  // event.data 就是 服務端返回回來的數據
            $('#id_'+response.cid).find('span').text(response.count);

        };

        function vote(cid) {
            ws.send(cid)   // 發送 websocket 數據
        }
    </script>
</body>
</html>

 


免責聲明!

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



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