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


    一、概述和项目结构

    在使用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       

    1. from flask import Flask,render_template,request,jsonify
    2. from flask_socketio import SocketIO,send,emit,join_room,leave_room
    3. app = Flask(__name__,static_folder='./static',template_folder='./templates')
    4. socketio = SocketIO(app,cors_allowed_origins='*',async_mode ='eventlet')
    5. from flask_socketio import ConnectionRefusedError
    6. '''
    7. 单对单聊天功能
    8. 1、用户连接时,携带上用户名,sid记录到该用户名的字典中
    9. 2、通过sid实现单聊
    10. 3、通过sid判断用户是否在线中
    11. '''
    12. USER = {} #{'lhz':{'sid':'xxxx'}}
    13. @app.route('/single/chat')
    14. def single():
    15. name = request.args.get('name')
    16. return render_template('chat/single.html',data={'name':name})
    17. class SingleChat(Namespace):
    18. def on_connect(self):
    19. name = request.args.get('name')
    20. sid = request.sid
    21. # 把当前用户写入到在线中
    22. if name in USER:
    23. print('有其他用户了', '直接覆盖')
    24. # raise ConnectionRefusedError('用户已经在线了')
    25. USER[name] = {'sid': sid}
    26. else:
    27. USER[name] = {'sid': sid}
    28. # send({'code':200,'msg':'使用send返回的,给connect事件'})
    29. #告诉在线用户,现在在线的用户情况
    30. online_users = [name_ for name_, dic in USER.items()]
    31. emit('connect',online_users,broadcast=True)
    32. def on_disconnect(self):
    33. sid = request.sid
    34. print('disconnect,','sid=',sid)
    35. del_name = False
    36. for name,dic in USER.items():
    37. if sid == dic.get('sid'):
    38. del_name = name
    39. break
    40. if del_name:
    41. USER.pop(del_name)
    42. print(USER,'当前用户消息')
    43. online_users = [name_ for name_, dic in USER.items()]
    44. emit('disconnect', {'leave':del_name,'online_users':online_users}, broadcast=True)
    45. def on_single_chat(self,data):
    46. name = data.get('name') #接收消息的用户
    47. msg = data.get('msg') #消息
    48. sendName = data.get('sendName') #发送消息的用户
    49. sid_dic = USER.get(name)
    50. if sid_dic:
    51. #给该用户发送消息
    52. emit('single_chat',{'name':sendName,'msg':msg},to=sid_dic.get('sid'))
    53. #告诉发送方,消息发送成功
    54. emit('success',{'code':200,'msg':msg,'name':name})
    55. print(name,'用户在线,可以发送')
    56. else:
    57. #告诉发送方,消息发送失败
    58. emit('success',{'code':400,'msg':'该用户不在线,无法发送消息'})
    59. print(name, '用户不在线,不可以发送')
    60. socketio.on_namespace(SingleChat('/single/chat'))
    61. if __name__ == '__main__':
    62. socketio.run(app,debug=True)

       

    2.3、single.html

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. <script type="application/javascript" src="/static/js/jquery-3.7.0.min.js">script>
    7. <script type="application/javascript" src="/static/js/socket.io_4.3.1.js">script>
    8. <script type="application/javascript">
    9. const data = {{ data|tojson }};
    10. const name = data.name; // 当前用户名
    11. //1、发起连接
    12. const socket = io('http://'+document.domain+':'+location.port+'/single/chat',
    13. {query:{'token':'123456','name':name}}
    14. );
    15. //2、监听connect事件,
    16. socket.on('connect',function (data) {
    17. console.log(data);
    18. const showDiv = $('#showDataId');
    19. if (data){
    20. //将当前用户的名字删除
    21. for (let i = data.length - 1; i >= 0; i--) {
    22. if (data[i] === name) {
    23. data.splice(i, 1);
    24. }
    25. }
    26. //展示在线的用户名
    27. if(data.length>=1){
    28. const pElement = $('

      ').text('[公告]在线的用户:'+data);

    29. //添加到展示的div标签中
    30. showDiv.append(pElement);
    31. }else{
    32. const pElement = $('

      ').text('[公告] 当前只有您在线...');

    33. //添加到展示的div标签中
    34. showDiv.append(pElement);
    35. }
    36. }
    37. });
    38. // 3、监听disconnect事件,展示退出的用户消息,通知其他人
    39. socket.on('disconnect',function (dic) {
    40. const showDiv = $('#showDataId');
    41. const data = dic.online_users;
    42. const leave = dic.leave;
    43. if (data){
    44. //将当前用户的名字删除
    45. for (let i = data.length - 1; i >= 0; i--) {
    46. if (data[i] === name) {
    47. data.splice(i, 1);
    48. }
    49. }
    50. // 1、展示谁离线了
    51. const pElement = $('

      ').text('[公告] '+leave+'离线了...');

    52. //添加到展示的div标签中
    53. showDiv.append(pElement);
    54. //2、展示还在线的用户
    55. if(data.length>=1){
    56. const pElement = $('

      ').text('[公告]在线的用户:'+data);

    57. //添加到展示的div标签中
    58. showDiv.append(pElement);
    59. }else{
    60. const pElement = $('

      ').text('[公告] 当前只有您在线...');

    61. //添加到展示的div标签中
    62. showDiv.append(pElement);
    63. }
    64. }
    65. });
    66. //4、监听单聊事件,single_chat
    67. socket.on('single_chat',function (data) {
    68. const sendName = data.name;
    69. const msg = data.msg;
    70. const showDiv = $('#showDataId');
    71. //展示别人发送的消息
    72. if(sendName===name){
    73. }else {
    74. const pElement = $('

      ').text(sendName+'>'+msg);

    75. //添加到展示的div标签中
    76. showDiv.append(pElement);
    77. }
    78. })
    79. //5、监听消息发送是否成功,失败时要展示
    80. socket.on('success',function (data) {
    81. const code = data.code;
    82. const msg = data.msg;
    83. const name = data.name;
    84. const showDiv = $('#showDataId');
    85. if (code===200){
    86. const pElement = $('

      ').text('you to('+name+') >'+msg);

    87. //添加到展示的div标签中
    88. showDiv.append(pElement);
    89. }else {
    90. alert(msg)
    91. }
    92. })
    93. //6、发送消息
    94. function sendMsg() {
    95. const recvName = $('#recvUserId').val();
    96. const msg = $('#inputDataId').val();
    97. socket.emit('single_chat',{'name':recvName,'msg':msg,'sendName':name})
    98. }
    99. script>
    100. head>
    101. <body>
    102. <div id="showDataId">
    103. div>
    104. <div>
    105. <p>
    106. <input type="text" id="recvUserId" value="接收用户">
    107. <input type="text" id="inputDataId" value="消息">
    108. <input type="button" id="submitId" value="发送消息" onclick="sendMsg()">
    109. p>
    110. div>
    111. body>
    112. 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的浏览器标签

  • 相关阅读:
    MySQL MHA
    用了半年chromium,说说心得
    阿里云高校计划学生和教师完成认证领取优惠权益
    Linux系统输出整数值的shell脚本
    xpath定位不包含某种属性的元素
    【gbase8a】docker搭建gbase8a,详细【图文】
    AWS API GATEWAY
    4-甲氧基三苯胺,CAS号:4316-51-2
    每日一练:LeeCode-9、回文数【字符串】
    Yii 结合MPDF 给PDF文件添加多行水印
  • 原文地址:https://blog.csdn.net/weixin_46371752/article/details/133158830