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

posted @ 2021-03-18 20:03  ShanCe-刘勇  阅读(533)  评论(0编辑  收藏  举报