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>
前端代码

 

posted @ 2019-07-15 20:36  Amorphous  阅读(441)  评论(0编辑  收藏  举报