在使用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.jshttps://code.jquery.com/jquery-3.7.0.min.jshttps://cdnjs.cloudflare.com/ajax/libs/socket.io/4.3.1/socket.io.min.jshttps://cdnjs.cloudflare.com/ajax/libs/socket.io/4.3.1/socket.io.min.js
1、先请求http://127.0.0.1:5000/single/chat?name=lhz 与后端建立连接,将会用户名与会话id绑定关系
2、指定消息发送给哪个用户
3、展示在线的用户名字,用户退出连接时通知其他用户
- 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)
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Titletitle>
- <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 = $('
'
).text('[公告]在线的用户:'+data); - //添加到展示的div标签中
- showDiv.append(pElement);
- }else{
- const pElement = $('
'
).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 = $('
'
).text('[公告] '+leave+'离线了...'); - //添加到展示的div标签中
- showDiv.append(pElement);
-
- //2、展示还在线的用户
- if(data.length>=1){
- const pElement = $('
'
).text('[公告]在线的用户:'+data); - //添加到展示的div标签中
- showDiv.append(pElement);
- }else{
- const pElement = $('
'
).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 = $('
'
).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 = $('
'
).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的浏览器标签