socketserver可用於實現併發通訊。html
socketserver 模塊簡化了編寫網絡服務程序的任務;同時 SocketServer 模塊也是 Python標準庫中不少服務器框架的基礎。
socketserver 模塊能夠簡化網絡服務器的編寫。Python把網絡服務抽象成兩個主要的類,一個是 Server 類,用於處理鏈接相關的網絡操做,另一個則是 RequestHandler 類,用於處理數據相關的操做;而且提供了兩個Mixin類,用於擴展 Server,實現多進程或多線程。前端
Server 類:
它包含了種五種server類,BaseServer(不直接對外服務)。TCPServer使用TCP協議,UDPServer使用UDP協議,還有兩個不常使用的,
即UnixStreamServer和UnixDatagramServer,這兩個類僅僅在unix環境下有用(AF_unix)。jquery
RequestHandler類:
全部requestHandler都繼承BaseRequestHandler基類。web
注: 全雙工管道通訊:既能夠 收,也能夠 發django
單工、半雙工和全雙工的區別: https://blog.csdn.net/starstar1992/article/details/53032409json
socketserver 的使用方法:flask
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 其實就是 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.htmlwebsocket
<!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>