WebSocket介绍
- 下载:pip install gevent-websocket
- WebSocket 是一种协议;是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议;
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,
允许服务端主动向客户端推送数据。
在 WebSocket API 中,
浏览器和服务器只需要完成一次握手,
两者之间就直接可以创建持久性的连接,并进行双向数据传输。
- 轮询:
是在特定的的时间间隔(如每1秒),
由浏览器对服务器发出HTTP请求,
然后由服务器返回最新的数据给客户端的浏览器。
传统轮询的缺点:
浪费资源,
服务器,客户端压力大
- 长轮询:
客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,
直到有新消息才返回响应信息并关闭连接,
客户端处理完响应信息后再向服务器发送新的请求。
优点:在无消息的情况下不会频繁的请求,耗费资源小。
缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。
实例:WebQQ、Hi网页版、Facebook IM。
- WebScoket:
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,
连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,
你可以通过 send() 方法来向服务器发送数据,
并通过 onmessage 事件来接收服务器返回的数据。
WebSocket+Flask开启一个WebSocket服务
- 示例:
from flask import Flask, request from geventwebsocket.handler import WebSocketHandler # 开启WebSocket协议的服务 from gevent.pywsgi import WSGIServer # WSGI 支持多线程的 socket from geventwebsocket.websocket import WebSocket app = Flask(__name__) @app.route("/ws") def ws(): # print(request.environ) # 打印原始的 request # print(request.environ.get("wsgi.websocket")) # 获取ws对象 ws = request.environ.get("wsgi.websocket") # type: WebSocket data = ws.receive() print(data) ws.send("发送消息给前端") if __name__ == '__main__': # 开启服务 http_serv = WSGIServer(("0.0.0.0", 5000), app, handler_class=WebSocketHandler) http_serv.serve_forever()
- 前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <body> <script> var ws = new WebSocket("ws://127.0.0.1:5000/we/" + username); ws.send("发送给客户端"); ws.onmessage = function (data) { console.log(data.data); } </script> </body> </html>
群聊小Demo
- 视图:
import json from flask import Flask, request, render_template from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer from geventwebsocket.websocket import WebSocket app = Flask(__name__) user_socket_list = [] @app.route("/ws") def ws(): # print(request.environ.get("wsgi.websocket")) user_web_socket = request.environ.get("wsgi.websocket") # type: WebSocket user_socket_list.append(user_web_socket) while 1: try: data = user_web_socket.receive() print(data) for user_socket in user_socket_list: if user_web_socket != user_socket: user_socket.send(data) except: user_socket_list.remove(user_web_socket) @app.route("/chat") def chat(): return render_template("ws.html") if __name__ == '__main__': http_serv = WSGIServer(("0.0.0.0", 5000), app, handler_class=WebSocketHandler) http_serv.serve_forever()
- 前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <body> <div> <p>发送消息:<input type="text" id="chat"> <button onclick="send_msg()">发送</button> </p> </div> <div id="msg"> </div> <script> var ws = new WebSocket("ws://127.0.0.1:5000/we"); ws.onmessage = function (data) { let p_tag = document.createElement("p"); p_tag.innerText = data.data; document.getElementById("msg").appendChild(p_tag); }; function send_msg() { var msg = document.getElementById("chat").value; ws.send(msg); } </script> </body> </html>
私聊小Demo
- 视图:
import json from flask import Flask, render_template, request from geventwebsocket.handler import WebSocketHandler # 开启WebSocket协议的服务 from gevent.pywsgi import WSGIServer # WSGI 支持多线程的 socket from geventwebsocket.websocket import WebSocket app = Flask(__name__) """ 实现单人聊天原理: 1,获取不同用户的用户名 1.1 利用字典的形式,用户名为key 2,获取指定发送到某用户的用户名 3,获取数据 """ web_socket_dict = {} @app.route("/we/<username>") def we(username): # print(request.environ) # 打印原始的 request # print(request.environ.get("wsgi.websocket")) # 获取ws对象 ws = request.environ.get("wsgi.websocket") # type: WebSocket web_socket_dict[username] = ws print(web_socket_dict) while 1: try: data_dict = ws.receive() # 等待接受消息 data = json.loads(data_dict) to_user = data.get("to_user") chat = data.get("chat") print(to_user, chat) to_from_ws = web_socket_dict.get(to_user) msg_data = {"from_user": username, "msg": chat} to_from_ws.send(json.dumps(msg_data)) except: pass # ws.send("哼!") # 接受到消息后,向前端发送消息 @app.route("/chat") def chat(): return render_template("chat.html") if __name__ == '__main__': http_serv = WSGIServer(("0.0.0.0", 5000), app, handler_class=WebSocketHandler) http_serv.serve_forever()
- 前端:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <body> <div> <p>请注册您的用户名:<input type="text" id="username"></p> <p>注册到服务器 <button onclick="send_username()">提交</button> </p> <p>请输入您要发送给谁:<input type="text" id="to_user"></p> <p>请输入您想发送的内容:<input type="text" id="chat"></p> <p> <button onclick="send_chat()">提交</button> </p> </div> <div id="msg"></div> <script> var ws = null; function send_username() { let username = document.getElementById("username").value; ws = new WebSocket("ws://127.0.0.1:5000/we/" + username); ws.onmessage = function (data) { console.log(data.data); let msg_data = JSON.parse(data.data); let ptag = document.createElement("p"); ptag.innerText = msg_data.from_user + " : " + msg_data.msg; document.getElementById("msg").appendChild(ptag); } } function send_chat() { let to_user = document.getElementById("to_user").value; let chat = document.getElementById("chat").value; let data = {to_user: to_user, chat: chat}; ws.send(JSON.stringify(data)); } </script> </body> </html>