• Flask-websocket实现聊天功能


    群聊无昵称

    原生js代码

    <!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>
    </body>
    <script type="application/javascript">
      var ws = new WebSocket("ws://192.168.16.42:9527/my_socket");
      // 监听后端发来的消息,ws.onmessage起到监听的作用,只要有消息过来函数会自动执行
      ws.onmessage = function (eventMessage) {
          console.log(eventMessage.data); // 获取后端发来的消息
          var p = document.createElement("p");
          p.innerText = eventMessage.data;
          document.getElementById("chat_list").appendChild(p); // 将消息内容添加到div内
      };
      // 将我们输入的内容发送给后端
      function send_msg() {
          var content = document.getElementById("content").value;
          ws.send(content);
      };
    
    </script>
    </html>

    后端逻辑代码

    # -*- coding: utf-8 -*-
    # @Time    : 2019/7/15 16:42
    
    from flask import render_template,request,Flask
    from geventwebsocket.handler import WebSocketHandler  # 提供WS协议处理
    from geventwebsocket.server import WSGIServer # 承载服务
    from geventwebsocket.websocket import WebSocket  # 语法提示
    
    app = Flask(__name__)
    
    user_socket_list = []
    @app.route("/my_socket")
    def my_socket():
        # 获取当前客户端与服务器的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)
            # 1 [<geventwebsocket.websocket.WebSocket object at 0x000001D0D70E1458>]
            # print(user_socket,"OK 连接已经建立好了,接下来发消息吧")
        while 1:
            # 等待前端将消息发送过来
            msg = user_socket.receive()
            print(msg)
    
            for usocket in user_socket_list:
                try:
                    usocket.send(msg)
                except:
                    continue
    
    @app.route("/qunliao")
    def gc():
        return render_template("qunliao.html")
    
    if __name__ == '__main__':
        http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler) # 这种启动方式和app.run()不冲突,该启动方式发什么请求都可以接受到
        http_serv.serve_forever()

    流程

    1、用户在网页请求http://192.168.16.42:9527/qunliao
    2、请求/qunliao这个路由走后端对应的视图函数gc返回qunliao.html这个页面,
    3、页面在加载的过程中走到script代码时建立WebSocket连接请求ws://192.168.16.42:9527/my_socket,
    4、ws://192.168.16.42:9527/my_socket请求走后端对应的视图函数,获取当前客户端与服务器的socket连接对象,调用该对象的receive方法,等待前端发来消息,
    5、前端我们通过给input框绑定点击事件,获取用户输入的内容发送给服务器;
    6、后端将前端发来的消息在发送给前端;
    7、前端通过ws.onmessage这个事件监听着后端过来的消息,只要有消息就会自动触发函数执行并获取数据;
    

    第一步是浏览器向/quliao这个路径发起请求:

    jQuery

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>群聊</title>
    </head>
    <body>
    <p>
        <input type="text" id="content">
        <button id="send_msg" >发送</button> <!--给按钮绑定点击事件-->
    </p>
    
    <div id="chat_list">
    
    </div>
    </body>
    <script src="/static/jquery-3.4.1.js"></script>
    <script type="application/javascript">
        var ws = new WebSocket("ws://192.168.16.42:9527/my_socket");
        // 监听后端发来的消息,ws.onmessage起到监听的作用,只要有消息过来函数会自动执行
        ws.onmessage = function (eventMessage) {
          console.log(eventMessage.data);       // 获取后端发来的消息
          var p = document.createElement("p"); // 创建一个p标签
          p.innerText = eventMessage.data;     // 将后端发来的数据添加到p标签内
          $("#chat_list").append(p)            // 将p标签添加到div内
        };
      // 将我们输入的内容发送给后端
        $("#send_msg").click(function () {
            var content = $("#content").val();
            ws.send(content);
        })
    </script>
    </html>
    前端代码
    from flask import render_template,request,Flask
    from geventwebsocket.handler import WebSocketHandler  # 提供WS协议处理
    from geventwebsocket.server import WSGIServer # 承载服务
    from geventwebsocket.websocket import WebSocket  # 语法提示
    app = Flask(__name__,static_folder="statics",static_url_path="/static")  # 获取静态文件
    user_socket_list = []
    @app.route("/my_socket")
    def my_socket():
        # 获取当前客户端与服务器的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)
            # 1 [<geventwebsocket.websocket.WebSocket object at 0x000001D0D70E1458>]
            # print(user_socket,"OK 连接已经建立好了,接下来发消息吧")
        while 1:
            # 等待前端将消息发送过来
            msg = user_socket.receive()
            print(msg)
            for usocket in user_socket_list:
                try:
                    usocket.send(msg)
                except:
                    continue
    
    @app.route("/qunliao")
    def gc():
        return render_template("qunliao.html")
    
    if __name__ == '__main__':
        http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
        http_serv.serve_forever()
    后端代码

    带群昵称的群聊

    通过动态路由参数获取前端传过来的用户名

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>群聊</title>
    </head>
    <body>
    <input type="text" id="username">
    <button id="login">登录</button>
    <p>
        <input type="text" id="content">
        <button id="send_msg" >发送</button> <!--给按钮绑定点击事件-->
    </p>
    
    <div id="chat_list">
    
    </div>
    </body>
    <script src="/static/jquery-3.4.1.js"></script>
    <script type="application/javascript">
        var ws = null; // 创建全局变量,ws多处使用
    
        $("#login").click(function () {
             var username = $("#username").val();
             console.log(username);
             // 创建一个websocket对象,建立websocket连接,更改了全局的ws,将用户名拼接上
             ws = new WebSocket("ws://192.168.16.42:9527/my_socket/" + username);
    
            // 监听后端发来的消息,ws.onmessage起到监听的作用,只要有消息过来函数会自动执行
            ws.onmessage = function (eventMessage) {
                console.log(eventMessage.data);       // 获取后端发来的消息
                var str_obj = JSON.parse(eventMessage.data);  // 反序列化,因为我们在发送给后端的时候是json
                var p = document.createElement("p"); // 创建一个p标签
                $(p).text(str_obj.from_user +":"+str_obj.chat);     // 将dom对象转换成jQuery对象,将后端发来的数据添加到p标签内
                $("#chat_list").append(p)            // 将p标签添加到div内
            };
        });
    
        // 将我们输入的内容发送给后端
        $("#send_msg").click(function () {
            var content = $("#content").val();
            var username = $("#username").val();
            // 将要发送的内容封装成自定义对象
            var sendStr = {
                from_user:username,
                chat:content
            };
            console.log(sendStr);
            // 序列化后发送给后端
            ws.send(JSON.stringify(sendStr));
        });
    </script>
    </html>
    前端代码
    from flask import render_template,request,Flask
    from geventwebsocket.handler import WebSocketHandler  # 提供WS协议处理
    from geventwebsocket.server import WSGIServer # 承载服务
    from geventwebsocket.websocket import WebSocket  # 语法提示
    app = Flask(__name__,static_folder="statics",static_url_path="/static")
    user_socket_dict = {}
    
    # 建立websocket连接时,前端将名字发送过来了
    @app.route("/my_socket/<username>")
    def my_socket(username):
        # 获取当前客户端与服务器的Socket连接
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    
        if user_socket:
            # 以名字为key,连接对象为value添加到字典中
            user_socket_dict[username] = user_socket
        while 1:
            # 等待前端将消息发送过来,此时是json数据
            msg = user_socket.receive()
            for usocket in user_socket_dict.values():
                try:
                    # 将收到的信息在发送给所有与服务器建立连接的前端
                    usocket.send(msg)
                except:
                    continue
    
    @app.route("/qunliao")
    def gc():
        return render_template("qunliaonicheng.html")
    
    if __name__ == '__main__':
        http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
        http_serv.serve_forever()
    后端代码

    效果:

    websocket实现私聊

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>群聊</title>
    </head>
    <body>
    我的昵称:<input type="text" id="username">
    <button id="login">登录</button>
    <p><input type="text" id="to_user">发送
        <input type="text" id="content">
        <button id="send_msg" >发送</button> <!--给按钮绑定点击事件-->
    </p>
    
    <div id="chat_list">
    
    </div>
    </body>
    <script src="/static/jquery-3.4.1.js"></script>
    <script type="application/javascript">
        var ws = null; // 创建全局变量,ws多处使用
    
        $("#login").click(function () {
             var username = $("#username").val();
             console.log(username);
             // 创建一个websocket对象,建立websocket连接,更改了全局的ws,将用户名拼接上
             ws = new WebSocket("ws://192.168.16.42:9527/my_socket/" + username);
    
            // 监听后端发来的消息,ws.onmessage起到监听的作用,只要有消息过来函数会自动执行
            ws.onmessage = function (eventMessage) {
                console.log(eventMessage.data);       // 获取后端发来的消息
                var str_obj = JSON.parse(eventMessage.data);  // 反序列化,因为我们在发送给后端的时候是json
                var p = document.createElement("p"); // 创建一个p标签
                $(p).text(str_obj.from_user +":"+str_obj.chat);     // 将dom对象转换成jQuery对象,将后端发来的数据添加到p标签内
                $("#chat_list").append(p)            // 将p标签添加到div内
            };
        });
    
        // 将我们输入的内容发送给后端
        $("#send_msg").click(function () {
            var content = $("#content").val();
            var username = $("#username").val();
            var to_user = $("#to_user").val();
            // 将要发送的内容封装成自定义对象
            var sendStr = {
                from_user:username,
                chat:content,
                to_user:to_user,
            };
            console.log(sendStr);
            // 序列化后发送给后端
            ws.send(JSON.stringify(sendStr));
        });
    </script>
    </html>
    前端页面
    import json
    from flask import render_template,request,Flask
    from geventwebsocket.handler import WebSocketHandler  # 提供WS协议处理
    from geventwebsocket.server import WSGIServer # 承载服务
    from geventwebsocket.websocket import WebSocket  # 语法提示
    app = Flask(__name__,static_folder="statics",static_url_path="/static")
    user_socket_dict = {}
    
    # 建立websocket连接时,前端将名字发送过来了
    @app.route("/my_socket/<username>")
    def my_socket(username):
        # 获取当前客户端与服务器的Socket连接
        user_socket = request.environ.get("wsgi.websocket")  # type:WebSocket
    
        if user_socket:
            # 以名字为key,连接对象为value添加到字典中
            user_socket_dict[username] = user_socket
        while 1:
            # 等待前端将消息发送过来,此时是json数据
            msg = user_socket.receive()
            print(msg)    # {"from_user":"wuchao","chat":"123","to_user":"xiaohei"}
            # 反序列化
            msg_dict = json.loads(msg)
            # 查找字典中前端要发送信息给那个人的名字
            to_username = msg_dict.get("to_user")
            # 获取目标人物的连接地址
            to_user_socket = user_socket_dict.get(to_username)
            # 将信息发送给目标人物
            to_user_socket.send(msg)
    
    @app.route("/siliao")
    def gc():
        return render_template("siliao.html")
    
    if __name__ == '__main__':
        http_serv = WSGIServer(("0.0.0.0",9527),app,handler_class=WebSocketHandler)
        http_serv.serve_forever()
    后端代码

    效果

  • 相关阅读:
    第三百六十九天 how can I 坚持
    第三百六十八天 how can I 坚持
    第三百六十四、五、六、七天 how can I 坚持
    POJ 1663:Number Steps
    POJ 2676:Sudoku 数独
    POJ 2488:A Knight's Journey 深搜入门之走马观花
    POJ 3050:Hopscotch
    51nod 1419:最小公倍数挑战
    POJ 1011:Sticks 经典搜索
    POJ 2362:Square 觉得这才算深度搜索
  • 原文地址:https://www.cnblogs.com/songzhixue/p/11190512.html
Copyright © 2020-2023  润新知