Flask框架-2-[单聊]: flask-socketio实现websocket的功能,实现单对单聊天,flask实现单聊功能

2023-09-22 10:15:20

一、概述和项目结构

在使用flask-socketio实现单聊时,需要将会话id(sid) 与用户进行绑定,通过emit('事件','消息',to=sid) ,就可以把消息单独发送给某个用户了。

flask_websocket

        |--static

                |--js

                        |--jquery-3.7.0.min.js

                        |--socket.io_4.3.1.js

        |--templates

                |--chat

                        |--single.html

        |--app.py

1.1、python版本

python3.9.0

1.2、依赖包

Flask==2.1.0
eventlet==0.33.3
Flask-SocketIO==5.3.4

1.3、js文件下载

https://code.jquery.com/jquery-3.7.0.min.jsicon-default.png?t=N7T8https://code.jquery.com/jquery-3.7.0.min.jshttps://cdnjs.cloudflare.com/ajax/libs/socket.io/4.3.1/socket.io.min.jsicon-default.png?t=N7T8https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.3.1/socket.io.min.js

       

二、具体代码

2.1、具体逻辑

1、先请求http://127.0.0.1:5000/single/chat?name=lhz     与后端建立连接,将会用户名与会话id绑定关系

2、指定消息发送给哪个用户

3、展示在线的用户名字,用户退出连接时通知其他用户

2.2、app.py       

from flask import Flask,render_template,request,jsonify
from flask_socketio import SocketIO,send,emit,join_room,leave_room

app = Flask(__name__,static_folder='./static',template_folder='./templates')
socketio = SocketIO(app,cors_allowed_origins='*',async_mode ='eventlet')
from flask_socketio import ConnectionRefusedError

'''
单对单聊天功能
1、用户连接时,携带上用户名,sid记录到该用户名的字典中
2、通过sid实现单聊
3、通过sid判断用户是否在线中
'''

USER = {}  #{'lhz':{'sid':'xxxx'}}

@app.route('/single/chat')
def single():
    name = request.args.get('name')
    return render_template('chat/single.html',data={'name':name})

class SingleChat(Namespace):
    def on_connect(self):
        name = request.args.get('name')
        sid = request.sid
        # 把当前用户写入到在线中
        if name in USER:
            print('有其他用户了', '直接覆盖')
            # raise ConnectionRefusedError('用户已经在线了')
            USER[name] = {'sid': sid}
        else:
            USER[name] = {'sid': sid}
            # send({'code':200,'msg':'使用send返回的,给connect事件'})

        #告诉在线用户,现在在线的用户情况
        online_users = [name_ for name_, dic in USER.items()]
        emit('connect',online_users,broadcast=True)

    def on_disconnect(self):
        sid = request.sid
        print('disconnect,','sid=',sid)
        del_name = False
        for name,dic in USER.items():
            if sid == dic.get('sid'):
                del_name = name
                break
        if del_name:
            USER.pop(del_name)
        print(USER,'当前用户消息')
        online_users = [name_ for name_, dic in USER.items()]
        emit('disconnect', {'leave':del_name,'online_users':online_users}, broadcast=True)

    def on_single_chat(self,data):
        name = data.get('name') #接收消息的用户
        msg = data.get('msg') #消息
        sendName = data.get('sendName') #发送消息的用户
        sid_dic = USER.get(name)
        if sid_dic:
            #给该用户发送消息
            emit('single_chat',{'name':sendName,'msg':msg},to=sid_dic.get('sid'))
            #告诉发送方,消息发送成功
            emit('success',{'code':200,'msg':msg,'name':name})
            print(name,'用户在线,可以发送')
        else:
            #告诉发送方,消息发送失败
            emit('success',{'code':400,'msg':'该用户不在线,无法发送消息'})
            print(name, '用户不在线,不可以发送')

socketio.on_namespace(SingleChat('/single/chat'))


if __name__ == '__main__':
    socketio.run(app,debug=True)

   

2.3、single.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="application/javascript" src="/static/js/jquery-3.7.0.min.js"></script>
    <script type="application/javascript" src="/static/js/socket.io_4.3.1.js"></script>
    <script type="application/javascript">
        const data = {{ data|tojson }};
        const name = data.name; // 当前用户名
        //1、发起连接
        const socket = io('http://'+document.domain+':'+location.port+'/single/chat',
            {query:{'token':'123456','name':name}}
        );


        //2、监听connect事件,
        socket.on('connect',function (data) {
            console.log(data);
            const showDiv = $('#showDataId');
            if (data){
                //将当前用户的名字删除
                for (let i = data.length - 1; i >= 0; i--) {
                    if (data[i] === name) {
                      data.splice(i, 1);
                    }
                  }
                //展示在线的用户名
                if(data.length>=1){
                    const pElement = $('<p>').text('[公告]在线的用户:'+data);
                    //添加到展示的div标签中
                    showDiv.append(pElement);
                }else{
                    const pElement = $('<p>').text('[公告] 当前只有您在线...');
                    //添加到展示的div标签中
                    showDiv.append(pElement);
                }
            }
        });

        // 3、监听disconnect事件,展示退出的用户消息,通知其他人
        socket.on('disconnect',function (dic) {
            const showDiv = $('#showDataId');
            const data = dic.online_users;
            const leave = dic.leave;
            if (data){
                //将当前用户的名字删除
                for (let i = data.length - 1; i >= 0; i--) {
                    if (data[i] === name) {
                      data.splice(i, 1);
                    }
                  }
                // 1、展示谁离线了
                const pElement = $('<p>').text('[公告] '+leave+'离线了...');
                //添加到展示的div标签中
                showDiv.append(pElement);

                //2、展示还在线的用户
                if(data.length>=1){
                    const pElement = $('<p>').text('[公告]在线的用户:'+data);
                    //添加到展示的div标签中
                    showDiv.append(pElement);
                }else{
                    const pElement = $('<p>').text('[公告] 当前只有您在线...');
                    //添加到展示的div标签中
                    showDiv.append(pElement);
                }
            }

        });

        //4、监听单聊事件,single_chat
        socket.on('single_chat',function (data) {
            const sendName = data.name;
            const msg = data.msg;
            const showDiv = $('#showDataId');
            //展示别人发送的消息
            if(sendName===name){

            }else {
                const pElement = $('<p>').text(sendName+'>'+msg);
                //添加到展示的div标签中
                showDiv.append(pElement);
            }
        })

        //5、监听消息发送是否成功,失败时要展示
        socket.on('success',function (data) {
            const code = data.code;
            const msg = data.msg;
            const name = data.name;
            const showDiv = $('#showDataId');
            if (code===200){
                const pElement = $('<p>').text('you to('+name+') >'+msg);
                //添加到展示的div标签中
                showDiv.append(pElement);
            }else {
               alert(msg)
            }
        })


        //6、发送消息
        function sendMsg() {
            const recvName = $('#recvUserId').val();
            const msg = $('#inputDataId').val();
            socket.emit('single_chat',{'name':recvName,'msg':msg,'sendName':name})
        }

    </script>
</head>
<body>
<div id="showDataId">

</div>
<div>
    <p>
        <input type="text" id="recvUserId" value="接收用户">
        <input type="text" id="inputDataId" value="消息">
        <input type="button" id="submitId" value="发送消息" onclick="sendMsg()">
    </p>

</div>

</body>
</html>

 三、代码测试

1、开启三个浏览器标签,分别输入

http://127.0.0.1:5000/single/chat?name=lhz

http://127.0.0.1:5000/single/chat?name=zzh

http://127.0.0.1:5000/single/chat?name=yf

2、两两之间互发消息

3、关闭lhz的浏览器标签

4、关闭zzh的浏览器标签

更多推荐

SpringBoot整合Flowable

1.配置(1)引入maven依赖<dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><!--MySQL连接

一款非常容易上手的报表工具,简单操作实现BI炫酷界面数据展示,驱动支持众多不同类型的数据库,可视化神器,免开源了

一款非常容易上手的报表工具,简单操作实现BI炫酷界面数据展示,驱动支持众多不同类型的数据库,可视化神器,免开源了。在互联网数据大爆炸的这几年,各类数据处理、数据可视化的需求使得GitHub上诞生了一大批高质量的BI工具。借助这些BI工具,我们能够大幅提升数据分析效率、生成更高质量的项目报告,让用户通过直观的数据看到结果

C语言生成随机数、C++11按分布生成随机数学习

C语言生成随机数如果只要产生随机数而不需要设定范围的话,只要用rand()就可以;rand()会返回一随机数值,范围在0至RAND_MAX间;RAND_MAX定义在stdlib.h,其值为2147483647;如果想要获取在一定范围内的数的话,直接做相应的除法取余即可;如何获取小数呢?例如,我们可以先获得10001以内

ELK日志分析系统+ELFK(Filebeat)

本章结构:1、ELK日志分析系统简介2、Elasticsearch介绍(简称ES)3、Logstash介绍4、Kibana介绍5、实验,ELK部署一、ELK日志分析系统简介ELK平台是一套完整的日志集中处理解决方案,将ElasticSearch、Logstash和Kiabana三个开源工具配合使用。可以提高安全性,集中

Ubuntu 20.04 安装 Franka Control Interface (FCI)

文章目录前言一、安装libfranka和franka_ros二、设置实时内核1.安装依赖2.编译内核3.安装内核4.验证内核三、在实时内核下安装显卡驱动1.切换回之前的内核2.切换至实时内核3.允许用户为其进程设置实时权限前言本文介绍在ubuntu20.04中安装FrankaControlInterface(FCI),

GAN里面什么时候用detach的说明

在生成对抗网络(GAN)中,生成器(G)和判别器(D)通常是两个独立的神经网络,它们之间会有梯度传播的互动。下面是一个简单的GAN的PyTorch实现,用于生成一维数据,以展示何时应该使用detach()。importtorchimporttorch.nnasnnimporttorch.optimasoptim#生成器

车辆检测:An Efficient Wide-Range Pseudo-3D Vehicle Detection Using A Single Camera

论文作者:ZhupengYe,YinqiLi,ZejianYuan作者单位:Xi'anJiaotongUniversity论文链接:http://arxiv.org/abs/2309.08369v1项目链接:https://www.youtube.com/watch?v=1gk1PmsQ5Q8内容简介:1)方向:车辆检

高并发场景下的接口调用优化

AI绘画关于SD,MJ,GPT,SDXL百科全书面试题分享点我直达2023Python面试题2023最新面试合集链接2023大厂面试题PDF面试题PDF版本java、python面试题项目实战:AI文本OCR识别最佳实践AIGamma一键生成PPT工具直达链接玩转cloudStudio在线编码神器玩转GPUAI绘画、A

网络安全(黑客)自学笔记

前言作为一个合格的网络安全工程师,应该做到攻守兼备,毕竟知己知彼,才能百战百胜。计算机各领域的知识水平决定你渗透水平的上限。【1】比如:你编程水平高,那你在代码审计的时候就会比别人强,写出的漏洞利用工具就会比别人的好用;【2】比如:你数据库知识水平高,那你在进行SQL注入攻击的时候,你就可以写出更多更好的SQL注入语句

数据字段保证唯一性

数据字段保证唯一性我们日常开发中,常见这么一个需求,要求一个code,一个name,需要保证code不重复,而code是用户输入的,常见的就比如一些字典等。这个的我们常见的几种做法的话。唯一键要么就是直接以code作为主键,这样的话,伪代码基本就是@Transactional(rollbackFor=Exception

在 Substance Painter中自定义Shader

为什么要学习在SubstancePainter中自定义Shader?答:需要实现引擎与SubstancePainter中的渲染效果一致,材质的配置也一致,所见即所得。基础概述首先在着色器设置这里,我们可以查看当前渲染使用的着色器如果没有着色器设置窗口,可以在窗口这里打开点击着色器名称,可以切换当前拥有的shader相应

热文推荐