• flask_socketio 学习


    此过程结合flask-socketio 和 sockeio.js 讲解

    1.初始 flask-socketio

    https://blog.csdn.net/eleanoryss/article/details/109600154

    这个链接是介绍 websocket 和 HTTP 长连接的差别

    websocket 说白一点就是,建立客户端和服务端双向通讯通道, 服务器可以主动向客户端发消息。

    https://www.jianshu.com/p/d81397edd2b1

    上边这个链接是一个对官方文档的翻译。

    2.安装

    python 3.9
    socket.io.js 3.1.3
    https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.js
    
    

    pip install flask-socketio

    依赖安装

    pip install eventlet

    3.初始化项目

    from flask_socketio import SocketIO
    import random
    async_mode = None
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'secret!'
    socketio = SocketIO(app)
    
    if __name__ == '__main__':
        socketio.run(app)
    # 或者 set flask_app=app  app指的是项目
    # flask run 
    
    # 两种方式都可以
    # socketio = SocketIO()
    # socketio.init_app(app)
    

    4. 客户端js

    相关文档

    https://socket.io/get-started/chat#Integrating-Socket-IO
    cdn 资源
    https://cdnjs.com/libraries/socket.io

    4.接收消息和发送消息

    客户端

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.js" integrity="sha512-2RDFHqfLZW8IhPRvQYmK9bTLfj/hddxGXQAred2wNZGkrKQkLGj8RCkXfRJPHlDerdHHIzTFaahq4s/P4V6Qig==" crossorigin="anonymous"></script>
    </head>
    <body>
    <script type="text/javascript">
        $(document).ready(function() {
            
            name_space = "/test";
            var socket = io.connect("http://127.0.0.1:5000");
            
            //  连接成功后发送消息
            socket.on("connect", function(){
                //  发送普通消息
                socket.send("connect once");
            })
            
    	   // 接受后台发送至ceishi的消息
            socket.on("ceshi", function(data){
                console.log("有名" + data)
            })
    
            // 接受后台消息
            socket.on("message", function(data){
                console.log("无名"+data)
            })
    
        });
    </script>
    </body>
    </html>
    

    后台

    @socketio.on("message")
    def message(msg):
        print("message", msg)
        socketio.send(msg, broadcast=True)
        socketio.emit('ceshi', "测试")
        
        
    #  接受 前端向json 接口发送的数据 对应前端 --> socket.emit("json", {"hello": "world"})
    @socketio.on("json")
    def json_msg(msg):
        print("json", msg)
        socketio.send(msg, broadcast=True)
    

    讲解:

    之前看文档不太明白,测试了好久.

    socketio 发送消息分为 send 和 emit

    ​ send(): 发送至未命名的一般默认为message, 一回来讲解message是什么

    ​ emit(): 发送到指定接受的活动上.

    socketio.on

    你可以认为这个是socketio 接收函数的接口, 用在客户端<前端>就相当于 websocket 的 ws.onmessage 接受后台传过来的数据, 用在后台同样

    socketio.emit("活动名", 消息, namespace<命名空间>)

    在上边代码有一句:

    socketio.emit('ceshi', "测试") # 这句话的意思是, 发送至活动ceshi 一条消息为 "测试"
    

    在客户端接收的地方为:

    socket.on("ceshi", function(data){
                console.log("有名" + data)
            }) # 接受后台发送到 ceshi 活动的信息
    

    后台同样:

    @socketio.on("message") # 接受发送到 message 活动的消息
    @socketio.on("json") # 接受发送到 json 活动的消息 
    @socketio.on("connect") # 当客户端连接的时候触发
    @socketio.on("disconnect") # 当客户端断开连接的时候触发
    # 除外你还可以自定义名字
    
    socketio.send

    不指定活动名发送, 一般默认发送到 message 中

    namespace: 下边讲解

    客户端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.js" integrity="sha512-2RDFHqfLZW8IhPRvQYmK9bTLfj/hddxGXQAred2wNZGkrKQkLGj8RCkXfRJPHlDerdHHIzTFaahq4s/P4V6Qig==" crossorigin="anonymous"></script>
    </head>
    <body>
    <script type="text/javascript">
        $(document).ready(function() {
            
            name_space = "/test";
            // 连接后台
            var socket = io.connect("http://127.0.0.1:5000");
            
            //  连接成功后发送消息
            socket.on("connect", function(){
                //  发送普通消息
                socket.send("connect once");
                // 发送json数据
                socket.emit("json", {"hello": "world"})
            })
    
            socket.on("ceshi", function(data){
                console.log("有名" + data)
            })
    
            // 接受后台消息
            socket.on("message", function(data){
                console.log("无名"+data)
            })
        });
    </script>
    </body>
    </html>
    

    后台代码:

    #encoding:utf-8
    #!/usr/bin/env python
    from flask import Flask, render_template
    from flask_socketio import SocketIO
    import random
    async_mode = None
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'secret!'
    socketio = SocketIO(app)
    
     
    @app.route('/')
    def index():
        return render_template('socketio.html')
     
    
    # 默认接受send 发送过来的, 同时也可以接受 emit("message", "测试")
    @socketio.on("message")
    def message(msg):
        print("message", msg)
        socketio.send(msg, broadcast=True)
        socketio.emit('ceshi', "测试")
    
    
    #  接受 前端向json 接口发送的数据 对应前端 --> socket.emit("json", {"hello": "world"})
    @socketio.on("json")
    def json_msg(msg):
        print("json", msg)
        socketio.send(msg, broadcast=True)
        
    if __name__ == '__main__':
        socketio.run(app, debug=True)
    

    *** 至此你可以通过将接受的数据添加到页面中的某个div,简单实现一个在线聊天

    broadcast = True

    这是 send 和 emit 的参数,指广播, 加上这个之后所有在指定命名空间中的客户端都会收到消息

    5. namespace

    namespace

    命名空间: 相当于 路由的name

    ​ 用来区分逻辑的,

    var socket = io.connect("http://127.0.0.1:5000"+"/ceshi"); # 指定连接 ceshi 命名空间
    

    后台使用:

    @socketio.on("ceshi", namespace="/ceshi")
    
    socketio.emit("ceshi", "message", namespace="/cesi")
    也可以在发送消息中使用指明发送的命名空间, 我测试后,发现只有声明作用并没有限制.
    

    6.room 房间

    在客户端方面房间的概念, 用来对用户分组,以便在某个命名空间下进一步的通信频道分离. 将客户端加入/迁出房间的操作在服务器端实现, join_room() 和 leave_room() , 还可以使用 close_room() 来删除房间, rooms () 函数返回房间客户端列表.

    为了保持简单,CatChat中并没有添加房间功能,我们这里仅介绍实现的基本方法。首先,你需要创建一个Room模型存储房间数据。房间可以使用任意的字符串或数字作为标识,所以可以使用主键列作为标
    识,另外再创建一个name列用于存储房间的显示名称。同时,我们还要在程序中提供房间的创建、编辑和删除操作。Room模型和表示用户的User模型建立一对多关系,分别建立Room.users和User.room关系属性。在房间的入口页面中,我们可以创建一个下拉列表供用户选择要加入的房间。用户提交表单后,程序会被重定向到房间聊天页面。在房间聊天页面,我们可以在客户端的connect事件监听函数中使用emit()函数触发服务器端自定义的join事件;同样,用户单击离开按钮离开房间后在客户端disconnect事件处理函数中使用emit()函数触发服务器端定义的leave事件:

    socket.on('connect', function() {
       socket.emit('join');
    });
    socket.on('disconnect', function() {
       socket.emit('leave');
    });
    

    JavaScript

    Copy

    在服务器端,自定义的join和leave事件分别用来将用户加入和移出
    房间,这两个自定义事件的处理函数如下所示:

    from flask_socketio import join_room, leave_room
    
    
    @socketio.on('join')
    def on_join(data):
        username = data['username']
        room = data['room']
        join_room(room)
        emit('status', username + ' has entered the room.', room=room)
    
    
    @socketio.on('leave')
    def on_leave(data):
        username = data['username']
        room = data['room']
        leave_room(room)
        emit('status', username + ' has left the room.', room=room)
    

    Python

    Copy

    在这两个事件处理器中,我们分别调用Flask-SocketIO提供的
    join_room()和leave_room()函数,并传入房间的唯一标识符。
    提示
    房间也支持命名空间,通过join_room()和leave_room()函数的
    namespace参数指定,默认使用当前正在处理的命名空间,可以通过
    Flask-SocketIO附加在请求对象上的namespace属性获得,即
    request.namesapce。
    同样,在发送事件时,也要指定发到哪个房间,这通过使用
    send()和emit()函数中的room参数来指定。比如,下面是创建广播
    新消息的room message事件处理函数:

    @socketio.on('room message')
    def new_room_message(message_body):
    	emit('message', {'message': current_user.username + ':' + message_body}, 			room=current_user.room)
    

    如果你仅需要对用户进行分组,那么房间是你的最佳选择。命名空
    间是在程序层面上的频道分离。如果我们要在程序中同时实现全局聊
    天、匿名聊天室、房间、私聊,这四类功能对消息的处理各自不同,所
    以我们需要为这四类功能指定不同的命名空间(全局聊天可以使用默认
    的全局命名空间)。在需要分离通信频道时,我们需要根据程序的特点
    来决定方式:仅使用命名空间、仅使用房间或两者结合使用。
    附注
    你可以通过Flask-SocketIO作者Miguel Grinberg提供的这个聊天程序
    https://github.com/miguelgrinberg/Flask-SocketIO-Chat)示例了解关于
    房间的具体实现。
    顺便说一下,基于房间你也可以实现私信/私聊功能。只需要把
    room设为代表某个用户的唯一值,在发送事件时,就只有目标用户的客
    户端才能接收到事件。你可以把这种实现方法理解为“一个人的房间”。
    这个能代表用户的唯一值可以是主键值、username或是Flask-SocketIO附
    加到request对象上代表每个客户端id的session id(request.sid)。
    提示
    如果你使用request.sid作为唯一值,那么需要在User模型中添加一个
    sid字段存储这个值,然后在服务器端的connect事件处理函数中更新这
    个值。

    https://huyu.info/blog/detail/103

  • 相关阅读:
    MySQL数据库分页
    Spring MVC
    Spring框架
    Java学习计划(转载)
    开发用户注册模块
    Ajax技术
    Jodd Email 发送邮件
    DOM技术
    MD5加密
    final关键字的使用
  • 原文地址:https://www.cnblogs.com/ShanCe/p/14555903.html
Copyright © 2020-2023  润新知