Flask 实现 WebSocket 通讯---群聊和私聊
一、WebSocket介绍
WebSocket是一种在单个TCP连接实现了服务端和客户端进行双向文本或二进制数据通信的一种通信的协议。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
一次请求 - 服务器收到请求 开始和客户端握手 - 保持长连接 - 数据实时 - 连接永远保持
优点:长连接 并且不影响 收发请求
缺点:连接保持,是需要资源的
二、 Flask 实现 WebSocket的基本用法
from geventwebsocket.server import WSGIServer # 我要WSGI为我提供服务 from geventwebsocket.handler import WebSocketHandler # WSGI 遇到 WS协议的时候,处理方式 from geventwebsocket.websocket import WebSocket # 语法提示 # 基于 Flask + geventwebsocket from flask import Flask,request,render_template app = Flask(__name__) if __name__ == '__main__': # app.run() # 启动服务 http_serv = WSGIServer(("0.0.0.0", 7856),application=app, handler_class=WebSocketHandler) http_serv.serve_forever()
三、Python + Flask 实现 WebSocket 通讯
1、实现简单群聊
后端代码 my_ws_ql.py:
from geventwebsocket.server import WSGIServer # 我要WSGI为我提供服务 from geventwebsocket.handler import WebSocketHandler # WSGI 遇到 WS协议的时候,处理方式 from geventwebsocket.websocket import WebSocket # 语法提示 # 基于 Flask + geventwebsocket from flask import Flask,request,render_template app = Flask(__name__) # 存储访问的连接 user_socket_list = [] @app.route('/ws') def my_ws_func(): user_socket = request.environ.get('wsgi.websocket') # type:WebSocket # user_socket_list.append(user_socket) # web + socket print(user_socket) # 浏览器发起的http请求 None # 用前端js发送的ws请求 <geventwebsocket.websocket.WebSocket object at 0x0000000003ADF2B8> while 1: msg = user_socket.receive() # 等待接收客户端发送过来的消息 for i in user_socket_list: # # 剔除自己的连接(不给自己推送自己发的消息,这样自己就看不到自己发的消息只能看到其他人发的) # if i == user_socket: # continue # 当循环到死链接时会抛出异常,这里捕捉一下,出现异常直接continue try: # 给其他连接推送消息 i.send(msg) except: continue print(msg) @app.route('/group_chat') def group_chat(): return render_template('group_chat.html') if __name__ == '__main__': # app.run() http_serv = WSGIServer(("0.0.0.0", 7856),application=app, handler_class=WebSocketHandler) http_serv.serve_forever()
前端模板代码 group_chat.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>发送消息>>> <input type="text" id="message"><button onclick="send_msg()">发送</button></p> <div id="message_list" style="width:500px;"> </div> </body> <script type="text/javascript"> var ws = new WebSocket("ws://192.168.15.37:7856/ws"); // 当ws 收到消息时执行 onmessage 属性 ws.onmessage = function (event) { console.log(event.data); // 创建p标签,将接收到的消息加入p标签中 var ptag = document.createElement("p"); ptag.innerText = event.data; // 将创建的p标签添加到页面中 var divtag = document.getElementById('message_list'); divtag.appendChild(ptag); }; function send_msg() { // 发送消息的函数 var msg = document.getElementById('message').value; ws.send(msg); } </script> </html>
2.实现简单的单独通讯
my_ws.py
import json from geventwebsocket.server import WSGIServer # 我要WSGI为我提供服务 from geventwebsocket.handler import WebSocketHandler # WSGI 遇到 WS协议的时候,处理方式 from geventwebsocket.websocket import WebSocket # 语法提示 from flask import Flask, render_template, request app = Flask(__name__) # user_socket_dict = {"ZWQ":<geventwebsocket.websocket.WebSocket object at 0x000002699374A730>, # "清风徐来":<geventwebsocket.websocket.WebSocket object at 0x000002699374A5F8>} user_socket_dict = {} @app.route('/ws/<nickname>') def my_ws_func(nickname): user_socket = request.environ.get("wsgi.websocket") # type: WebSocket user_socket_dict[nickname] = user_socket print(len(user_socket_dict), user_socket_dict) # web + socket # print(user_socket) while 1: msg = user_socket.receive() # 等待接收客户端发送过来的消息 print(msg) msg = json.loads(msg) # Dict """ Dict { to_user:ZWQ from_user:清风徐来 message: "我是清风徐来发给ZWQ的一条消息" } """ to_user_socket = user_socket_dict.get(msg.get("to_user")) # 获取发送地址 msg_json = json.dumps(msg) to_user_socket.send(msg_json) @app.route('/private_chat') def privatre_chat(): return render_template('private_chat.html') if __name__ == '__main__': http_ws = WSGIServer(("0.0.0.0",7856), application=app,handler_class=WebSocketHandler) http_ws.serve_forever()
模板代码 private_chat.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>登录名 :<input type="text" id="nick"> <button onclick="login()">登录</button></p> <p> 给 <input type="text" id="to_user"> </p> <p> 发送消息: <input type="text" id="message"><button onclick="send_msg()">发送</button> </p> <div id="message_list" style="width: 500px"> </div>> </body> <script type="text/javascript"> var ws = null; function send_msg() { var msg = document.getElementById('message').value; var to_user = document.getElementById('to_user').value; var nick = document.getElementById('nick').value; var msg_obj = { to_user:to_user, from_user:nick, msg:msg }; var msg_json = JSON.stringify(msg_obj); ws.send(msg_json); } function login() { var nick = document.getElementById("nick").value; ws = new WebSocket("ws://192.168.15.33:7856/ws/"+nick); // 收到消息执行onmessage属性 ws.onmessage = function (event) { data_obj = JSON.parse(event.data); // 将JSON数据反序列化 var ptag = document.createElement('p'); ptag.innerText = data_obj.from_user + ":" + data_obj.msg; var divtag = document.getElementById('message_list'); divtag.appendChild(ptag); } } </script> </html>