32 websocket通讯实现
32 websocket通讯实现
写在前面:
php服务端使用的是已经封装好了的workman实现websocket服务端功能
uniapp客户端使用的是uniapp内置的showcketTask api 实现websocket客户端功能
换句话说用的都是别人已经封装好的了。
如果想深入研究建议参考 炎龙的 智能玩具websocket部分视频
一 通讯原理
1 客户端wss请求连接,服务端返回建立连接成功
2 服务端wss向客户端发送客户端的id,并且告诉客户端需要绑定
{
"type": "bind",
"data": "7f0000010b5700000004"
}
3 客户端带着自己的user_id ,ajax请求服务端绑定
4 服务端以后根据user_id 向绑定了该user_id 的所有客户端进行发送信息。
5 客户端wss绑定user_id成功后:
-
关于即时通讯功能,以后wss只用于接受服务端的信息
-
客户端以后依旧使用ajax向服务端提交即时通讯信息。
精炼:websocket只接受连接并不接受通讯内容。通过http来的通讯内容经过websoket推送给具体的user_id
二 服务端接口
(wss )1 监听websocket连接,并且给其返回连接成功,并且再发一条(客户端id,并且要求绑定。)
(http)2 绑定上线,监听客户端请求绑定user_id。
(http)3 接受客户端要发送的聊天内容
- 如果发送内容的收件人在线wss直接发送信息给收件人,http返回ok。 (ps:该php后端并没有存储到数据库中)。
- 如果发送内容的收件人不在线直接缓存到redis里面,http返回ok。 (ps:该php后端并没有把聊天内容存储到数据库中)。
(http)4 判断用户是否在线,从缓存里直接拿出来缓存的未读信息,然后直接给客户端返回。
三 客户端
1 没有登录成功
- 不触发socket事件
2 登录成功后
- 打开socket
- 监听服务端消息
- 绑定用户
- http查看不在线未读消息
- 更新通讯列表,更新与人通讯详情列表,更新未读数下角标
3 app开启的时候,并且已经登录了(绑定服务端+读取未读消息)
- 打开socket
- 监听服务端消息
- 绑定用户
- http查看不在线未读消息
- 更新通讯列表,更新与人通讯详情列表,更新未读数下角标
4 app开启的时候,并且已经登录了(开始接受消息)
ps:getter来处理未读数量问题,好处待定。
一 用户不操作的情况
- 监听服务端消息。
- Index根据ToUser,判断是否正在根这个人聊天
- 第一种:如果和这个人正在聊天,
- 1 userchat页面$on接受到VUEX传来的信息进行渲染
- 2 不用更新下角标未读数。
- 3 更新state里面的两个通讯表
- 4 更新本地通讯列表
- 5 更新本地与人通讯详情列表
- 第二种:如果和这个人没有正在聊天(也就是ToUser为空,并且意味着user-chat关闭的)
- 1 更新下角标未读数。
- 2 更新本地通讯列表
- 3 更新本地与人通讯详情列表
二 用户操作的情况
用户察觉到了未读下角标,然后点击该通讯列表的某人:
- 1 action然后点开页面清空下角标。
- 2 action然后打开页面加载与人通讯详情列表,渲染页面。
5 登录了,app已经打开了(发送消息)
- 一定是打开了与某人聊天的页面。
- 然后触发submit事件。
- action里面更新与某个用户的消息记录并存储到本地。
- action里面更新用户通讯表并存储到本地。
- 返回格式化好的数据,http发送到服务端。
- 把发送的信息渲染到与这个人聊天页面。
四 插播async+await
精华:
// 案例:
async xxxx(){
setTimeout(()=>{
console.log('settimeout内部谁都没有等我')
},4000)
console.log('xxxx说我并不会等setTimeout')
}
async f1(){
await xxxx()
console.log('f1输出')
}
f1()
// 输出:
// xxxx说我并不会等setTimeout
// f1输出
// settimeout内部谁都没有等我
// await xxxx()
// await只能保证xxx()产生的promise对象等到了resolve拿到了返回结果(站在函数的角度就是产生了执行到了return)
// 但是await并不能保证xxx()函数体里面的异步代码也会执行完,
// 如果想要保证xxx()里面的异步代码也执行完了,需要在xxxx函数内部定制await。
// xxxx()不写await, 直接返回一个promise对象,并不会在此刻等到执行完函数体代码。
// **精炼**:await 能保证promise拿到resolve,不能保证await的async函数内部异步执行完。
案例:
<template>
<view>
<!-- 测试foreach -->
<!-- <view class="font" click="testList">测试{{list}}</view> -->
<!-- 测试web-view -->
<!-- <web-view src="/hybrid/html/dongxiao2/index.html" @message="getMes
sage"></web-view> -->
<button type="default" class="bg-main text-white rounded" style="width: 500rpx;" @click="func1">点我测试async+await</button>
</view>
</template>
<script>
export default {
data() {
return {
// list : [4,3,2,1]
}
},
methods: {
getMessage(e){
console.log(e)
},
testList(){
},
async func1(){
console.log('func1')
await this.func2()
// func2本身是个异步函数,也就是func2加括号执行直接返回个promise对象。
// 如果不写await 直接返回promise对象,并不会等到promise里面的resolve,也就是并不会等到函数体的同步代码执行到最后一行,也就是不会等到return执行。
// 如果写了await 那么就会等到这个func2的promise对象产生了resolve拿到值,继续往下执行,也就意味着async func2会”完整“执行一遍
// 前方高能:坑来了!!!!
// 上面提到的“完整”打了引号证明是不对的,注意:那是否可以理解await作用下的 func2已经完整执行完了?答案是错!!!!
// 来 跟我把视角定位async func2 函数体代码。
// 思考如下代码func2体里面有异步代码this.func4(),当这个异步只是返回promise对象,就接着往下执行console.log('func2')
// 并没有等到this.func4()的该promise对象拿到resolve。
// 也就是func2里的this.func4()这个异步还没有执行完,就已经开始执行了fun1()里的this.func3()
// 结论:
// 所以await xxxx()
// await只能保证xxx()产生的promise对象等到了resolve拿到了返回结果(站在函数的角度就是产生了执行到了return)
// 但是await并不能保证xxx()函数体里面的异步代码也会执行完,
// 如果想要保证xxx()里面的异步代码也执行完了,需要在xxxx函数内部定制await。
// xxxx()不写await, 直接返回一个promise对象,并不会在此刻等到执行完函数体代码。
// **精炼**:await 能保证promise拿到resolve,不能保证await的async函数内部异步执行完。
// 执行结果如下:
// 12:59:04.539 func1 at pages/test2/test2.vue:30
// 12:59:04.562 func2 at pages/test2/test2.vue:37
// 12:59:04.586 func3 at pages/test2/test2.vue:41
// 12:59:06.546 func4 at pages/test2/test2.vue:45
// 12:59:07.538 func5 at pages/test2/test2.vue:51
// 要明白这样只会让func2的代码完整执行完,不会让func2里面的异步代码
await this.func3()
},
async func2(){
this.func4()
console.log('func2')
},
async func3(){
this.func5()
console.log('func3')
},
async func4(){
setTimeout(()=>{
console.log('func4')
},2000)
},
async func5(){
setTimeout(()=>{
console.log('func5')
},3000)
},
}
}
</script>
<style>
</style>