Flask应用之websocket
uwsgi协议封装的request.environ()数据
一、配置gevent-websocket
#安装:pip install gevent-websocket
#开启gevent-websocket服务: http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler) http_serv.serve_forever()
二、web浏览器请求数据内容
web通过http请求的返回的environ数据:
environ数据: {'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'gevent/1.4 Python/3.6', 'SCRIPT_NAME': '', 'wsgi.version': (1, 0), 'wsgi.multithread': False,
'wsgi.multiprocess': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>,
'SERVER_NAME': 'DESKTOP-JNSGT4U', 'SERVER_PORT': '9527', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/my_socket', 'QUERY_STRING': '', 'SERVER_PROTOCOL': 'HTTP/1.1',
'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '51956', 'HTTP_HOST': '127.0.0.1:9527', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0',
'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36',
'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br',
'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'wsgi.input': <gevent.pywsgi.Input object at 0x000001EA38EA94C8>,
'wsgi.input_terminated': True, 'werkzeug.request': <Request 'http://127.0.0.1:9527/my_socket' [GET]>}
请求头headers数据: Host: 127.0.0.1:9527 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9
web通过websocket请求的返回的environ数据:
environ数据: {'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_SOFTWARE': 'gevent/1.4 Python/3.6', 'SCRIPT_NAME': '', 'wsgi.version': (1, 0), 'wsgi.multithread': False,
'wsgi.multiprocess': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>,
'SERVER_NAME': 'DESKTOP-JNSGT4U', 'SERVER_PORT': '9527', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/my_socket', 'QUERY_STRING': '', 'SERVER_PROTOCOL': 'HTTP/1.1',
'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': '52075', 'HTTP_HOST': '127.0.0.1:9527', 'HTTP_CONNECTION': 'Upgrade', 'HTTP_PRAGMA': 'no-cache',
'HTTP_CACHE_CONTROL': 'no-cache', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36',
'HTTP_UPGRADE': 'websocket', 'HTTP_ORIGIN': 'http://localhost:63342', 'HTTP_SEC_WEBSOCKET_VERSION': '13', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br',
'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_SEC_WEBSOCKET_KEY': 'KttfJvW4Vt/KTuFudtOf2g==', 'HTTP_SEC_WEBSOCKET_EXTENSIONS': 'permessage-deflate; client_max_window_bits',
'wsgi.input': <gevent.pywsgi.Input object at 0x000001EA38EA9B88>, 'wsgi.input_terminated': True, 'wsgi.websocket_version': '13',
'wsgi.websocket': <geventwebsocket.websocket.WebSocket object at 0x000001EA38EEE2B8>, 'werkzeug.request': <Request 'http://127.0.0.1:9527/my_socket' [GET]>}
请求头headers数据: Host: 127.0.0.1:9527 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Upgrade: websocket == Websocket 请求 WebSocketHandler 处理的 Key Origin: http://localhost:63342 Sec-Websocket-Version: 13 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Sec-Websocket-Key: KttfJvW4Vt/KTuFudtOf2g== Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits
三、Websocket请求数据方式
通过web控制台,创建客户端websocket连接:
ws = new WebSocket("ws://127.0.0.1:9527/my_socket"); # 创建连接 ws.sed("hello world!") # 发送数据
通过前端代码,创建客户端websocket连接:
<script type="application/javascript"> // 创建链接 var ws = new WebSocket("ws://192.168.16.40:9527/my_socket"); ... </script>
四、Websocket连接数据状态码
WebSocket链接状态码:
WebSocket链接状态码: readlyState:0 // 当前与服务器的连接没有建立 readlyState:1 // 与服务器的连接已建立,等待数据传输 readlyState:3 // 服务端连接已断开
web控制台图例:
五、Websocket连接,客户端接收消息体
MessageEvent消息体中存放从服务端接收的所有信息,data参数是我们需要的内容
客户端接收信息,js代码实现: // 监听电话(接收消息),当消息到来时onmessage,处理function函数 ws.onmessage = function (eventMessage) { // 在消息体重获取data具体信息内容 console.log(eventMessage.data); // 创建一个p标签 var p = document.createElement("p"); // 添加标签内容 p.innerText = eventMessage.data; // 在div标签中添加p标签 document.getElementById("chat_list").appendChild(p); };
控制台图例:
六、websocket应用实例1
后端数据:
from flask import Flask, request, render_template from geventwebsocket.handler import WebSocketHandler # 提供WS协议处理 from geventwebsocket.server import WSGIServer # 承载服务 from geventwebsocket.websocket import WebSocket # 语法提示 app = Flask(__name__) # 存储客户端对象列表 user_socket_list = [] # web客户端连接测试 @app.route("/my_socket") def my_socket(): # print(request.environ, ">>>") # print(request.headers, "<<<") # 获取当前客户端与服务器的Socket连接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket if user_socket: user_socket_list.append(user_socket) print(len(user_socket_list), user_socket_list) while True: # 接收客户端信息 msg = user_socket.receive() print(msg) # 遍历列表,给所有客户端发送信息 for usocket in user_socket_list: try: # 服务端把接收的数据返回给每个客户端 usocket.send(msg) except Exception: # 如果存在某个用户断开连接,则跳过当前服务器报错 continue # 群聊客户端连接测试 @app.route("/gc") def gc(): return render_template("websocket1.html") if __name__ == '__main__': # 配置websocket服务 http_server = WSGIServer(("0.0.0.0", 5000), app, handler_class=WebSocketHandler) # 启动服务 http_server.serve_forever()
前端文件配置:
在javascript里面实现,启动 ws://127.0.0.1:5000/ 服务
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>群聊</title> </head> <body> <p><input type="text" id="content"><button onclick="send_msg()">发送</button></p> <div id="chat_list"></div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script> // 创建客户端连接 var ws = new WebSocket("ws://127.0.0.1:5000/my_socket"); // 监听电话(接收消息),当消息到来时onmessage,处理function函数 ws.onmessage = function (eventMessage) { // 在消息体重获取data具体信息内容 console.log(eventMessage.data); // 创建一个p标签 var p = document.createElement("p"); // 添加标签内容 p.innerText = eventMessage.data; // 在div标签中添加p标签 document.getElementById("chat_list").appendChild(p); }; // 发送消息 function send_msg() { // 获取input标签的内容 var content = document.getElementById("content").value; // 给服务端发送信息 ws.send(content); }; </script> </body> </html>
七、websocket应用实例2
群聊测试:
from flask import Flask, request, render_template from geventwebsocket.handler import WebSocketHandler # 提供WS协议处理 from geventwebsocket.server import WSGIServer # 承载服务 from geventwebsocket.websocket import WebSocket # 语法提示 app = Flask(__name__) # 存储客户端对象字典 user_socket_dict = {} # web客户端连接测试 @app.route("/my_socket/<username>") def my_socket(username): # 获取当前客户端与服务器的Socket连接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket user_socket_dict[username] = user_socket print(len(user_socket_dict), user_socket_dict) while True: msg = user_socket.receive() print(msg) # 遍历字典的值,把客户端接收的信息发送给每一个用户 for usocket in user_socket_dict.values(): try: usocket.send(msg) except: continue # 群聊客户端连接测试 @app.route("/gc") def gc(): return render_template("websocket2.html") if __name__ == '__main__': # 配置websocket服务 http_server = WSGIServer(("0.0.0.0", 5000), app, handler_class=WebSocketHandler) # 启动服务 http_server.serve_forever()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>群聊</title> </head> <body> <p>用户名:<input type="text" id="username"><button onclick="loginGc()">登录</button></p> <p>发送内容:<input type="text" id="content"><button onclick="send_msg()">发送</button></p> <div id="chat_list"></div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script> function loginGc() { // 获取input标签的用户名 var username = document.getElementById("username").value; // 创建客户端连接 ws = new WebSocket("ws://127.0.0.1:5000/my_socket/" + username); // 监听电话(接收消息),当消息到来时onmessage,处理function函数 ws.onmessage = function (eventMessage) { // 在消息体重获取data具体信息内容 console.log(eventMessage.data); str_obj = JSON.parse(eventMessage.data); // 创建一个p标签 var p = document.createElement("p"); // 添加标签内容 p.innerText = str_obj.from_user + str_obj.chat; // 在div标签中添加p标签 document.getElementById("chat_list").appendChild(p); }; } // 发送消息 function send_msg() { // 获取input标签中的用户名 var username = document.getElementById("username").value; // 获取input标签的发送内容 var content = document.getElementById("content").value; var sendStr = { from_user:username, chat:content }; // 给服务端发送信息 ws.send(JSON.stringify(sendStr)); }; </script> </body> </html>
八、websocket应用实例3
私聊测试:
import json from flask import Flask, request, render_template from geventwebsocket.handler import WebSocketHandler # 提供WS协议处理 from geventwebsocket.server import WSGIServer # 承载服务 from geventwebsocket.websocket import WebSocket # 语法提示 app = Flask(__name__) # 存储客户端对象字典 user_socket_dict = {} # web客户端连接测试 @app.route("/my_socket/<username>") def my_socket(username): # 获取当前客户端与服务器的Socket连接 user_socket = request.environ.get("wsgi.websocket") # type:WebSocket user_socket_dict[username] = user_socket print(len(user_socket_dict), user_socket_dict) while True: # 获取到用户 msg = user_socket.receive() msg_dict = json.loads(msg) # 获取当前登录用户的用户名 to_user_nick = msg_dict.get("to_user") print(to_user_nick) # 找到当前登录的用户 usocket = user_socket_dict.get(to_user_nick) usocket.send(msg) # 群聊客户端连接测试 @app.route("/gc") def gc(): return render_template("websocket3.html") if __name__ == '__main__': # 配置websocket服务 http_server = WSGIServer(("0.0.0.0", 5000), app, handler_class=WebSocketHandler) # 启动服务 http_server.serve_forever()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>群聊</title> </head> <body> <p>用户名:<input type="text" id="username"><button onclick="loginGc()">登录</button></p> <p>接收用户:<input type="text" id="to_user">发送内容:<input type="text" id="content"><button onclick="send_msg()">发送</button></p> <div id="chat_list"></div> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script> <script> function loginGc() { // 获取input标签的用户名 var username = document.getElementById("username").value; // 创建客户端连接 ws = new WebSocket("ws://127.0.0.1:5000/my_socket/" + username); // 监听电话(接收消息),当消息到来时onmessage,处理function函数 ws.onmessage = function (eventMessage) { // 在消息体重获取data具体信息内容 console.log(eventMessage.data); str_obj = JSON.parse(eventMessage.data); // 创建一个p标签 var p = document.createElement("p"); // 添加标签内容 p.innerText = str_obj.from_user + str_obj.chat; // 在div标签中添加p标签 document.getElementById("chat_list").appendChild(p); }; } // 发送消息 function send_msg() { // 获取input标签中的用户名 var username = document.getElementById("username").value; // 获取input标签中的接收用户名 var to_user = document.getElementById("to_user").value; // 获取input标签的发送内容 var content = document.getElementById("content").value; var sendStr = { from_user:username, to_user:to_user, chat:content }; // 给服务端发送信息 ws.send(JSON.stringify(sendStr)); }; </script> </body> </html>
https://www.cnblogs.com/WiseAdministrator/