当前位置:首页 > WebSocket > 正文内容

uniapp的websocket无法监听到onSocketClose和onSocketError

陈杰2个月前 (12-28)WebSocket374

项目框架使用的前端uniapp+后端laravel+workerman websocket写的,主要功能是聊天室系统。


但是在开发完成实际体验过程中发现了一个有趣的现象。


websocket老是无缘无故的断开,且没有触发 onSocketClose和onSocketError回调。


查找原因吧,结果发现


在开发过程中基本上是马上写了就马上就测试了,没有长时间的链接测试。客户在使用过程中,一天都把聊天室挂上的,可能早上挂上了,一上午都没有发送消息,然后中午来发消息发现链接被断开了。。


猜测一下,有可能是防火墙或者啥啥啥的玩意把我们的聊天室链接kill掉了或者网络波动等一众原因吧,(反正就是非正常断开链接)


我们之前的用了一个值来存储websocket是否处于链接状态,当发送断开回调或者错误回调的使用就去尝试重新连接,但是没有触发回调也就没有去尝试重新连接了。


上解决方案吧,利用websocket的心跳来做链接存活检查


讲解一下思路:

在我们连接到websocket服务后需要设置一个定时器来向服务器发送心跳数据包(让服务器知道我还活着)。

一般来说服务器也会发送一个收到心跳数据包的回复,我这里定义为ping和pong。

客户端ping服务端,服务器pong客户端。

再每次收到服务器的pong数据包的时候我就记录一下收到该心跳回复数据时候的时间戳。

有了这个时间戳我们就知道当前的websocket服务链接是否被非正常关闭了。

例如我们的心跳时间为20秒,我们设置一个25秒的定时器,那5秒留给网络波动的冗余,用定时器来检测如果时间戳已经20秒没更新了那么就说明我们的websocket断开了需要重连。

我们这里直接用用定时器继续调用

this.socket.open()


方法就行了,因为在open方法中也已经写上了,如果时间戳更新了就不需要重连,提示了

console.log("socket已经开启");

但是如果时间戳没被正确更新,那么重连就是了,并且重连时间就是我们这个定时器的时间周期


当然还有另外一种方式,既然有心跳,那么在发送心跳的地方

uni.sendSocketMessage({
	data: {type:"ping"},
	success: (s) => {},
	fail: (f) => {
		onsole.log(f);
	}
})

fail失败回调里面也行,也可以判断,当时这种方式有一个问题就是,如果出于其他原因导致的发送失败会造成我们误判链接被关闭了(实际上链接没被关闭,只是发送失败了)


所以多种方法结合起来更好


下面上代码吧


import request from './request.js';
export default {
	list: [],
	isLogin: false,
	url: 'wss://chat.nnjingfang.com/wss',
	ST: false,
	ping: '',
	t1: '',
	isOpen: false,
	pongTime: 0,

	open() {
		let time = Math.round(new Date() / 1000)
		console.log(time - this.pongTime);

		if ((time - this.pongTime) < 60) {
			//链接是开启的
			console.log("socket已经开启");
			return;
		}
		this.ST = uni.connectSocket({
			url: this.url,
			complete: (e) => {},
			fail: (f) => {
				console.log(f);
			},
			success: (s) => {
				//this.isLogin = true
			}
		});
		if (!this.ST) return //防止错误open

		this.ST.onOpen(() => {
			this.isLogin = true
			this.pongTime = Math.round(new Date() / 1000)
			console.log('连接成功');
			this.t1 = window.setInterval(() => {
				let msg = JSON.stringify({
					'type': 'ping',
					'data': {
						uid: request.uid,
					}
				})
				uni.sendSocketMessage({
					data: msg,
					success: (s) => {}
				})
			}, 20000);
		})

		this.ST.onMessage((res) => {
			let ret = JSON.parse(res.data)
			if (ret) {
				if (ret.code == 200) {
					if (ret.type == "pong") {
						this.pongTime = Math.round(new Date() / 1000)
					}
					if (ret.type == "init") {
						let msg = JSON.stringify({
							'type': 'bind',
							'data': {
								uid: request.uid,
								token: request.token,
								datatype: request.datatype
							}
						})
						uni.sendSocketMessage({
							data: msg
						})
					}
					if (ret.type == "user" || ret.type == "system") {
						if (this.list[ret.gid]) {
							console.log(ret);
							this.list[ret.gid].list.push(ret)
							if (ret.msg.userinfo.uid !== request.uid) {
								this.list[ret.gid].config.number += 1
							}
							uni.$emit('update', ret)
						}
					}
				} else {
					uni.showToast({
						title: ret.msg,
						icon: 'loading'
					})
				}
			}
		})
		uni.onSocketOpen(function(res) {
			console.log('WebSocket连接已打开!');
		});
		uni.onSocketClose((res) => {
			uni.showToast({
				title: '与服务器连接中断,请重新刷新页面!',
				icon: 'loading'
			})
			window.clearInterval(this.t1);
			this.isLogin = false
			this.ST = false
			setTimeout(() => {
				this.open()
			}, 5000)
		});
		uni.onSocketError((res) => {
			uni.showToast({
				title: '与服务器连接错误,请重新刷新页面!',
				icon: 'loading'
			})
			this.isLogin = false
			this.ST = false
			setTimeout(() => {
				this.open()
			}, 5000)
		});
	},
}



扫描二维码至手机访问

扫描二维码推送至手机访问。

版权声明:本文由何烦过虎溪发布,如需转载请注明出处。

转载请注明出处:http://95shouyou.com/?id=26

分享给朋友:

相关文章

Workerman-写一个简单的websocket双向通信并实现MVC,用来开发游戏服务器

最近在看Workerman,发现这是一个真的很好用的东西。文档相当丰富,而且大神walker很贴心,有问必答。下面记一下一个简单的基于GatewayWorker框架写的websocket的程序。传统的...

申研社websocket通信规定

一、建立连接和维持连接 1、建立连接 测试地址ws://api.shenyanshe.95shouyou.com/websocket 2、约定客户端发送数据格式为 json字符串,...

nginx下反向代理开启websocket的wss服务

nginx下反向代理开启websocket的wss服务

通过nginx配置好网站的ssl证书后添加   location /wss  {    proxy_pass http://127.0.0.1:828...

workerman拆分events文件,实现常规编程习惯

workerman拆分events文件,实现常规编程习惯

wokerman的gateway很好用,自动解决了扩展性,分布式等较底层的东西。所有的逻辑代码只需要专注于events.php文件就行了,但是作者对于events编程的介绍比较少,如果从业多年的老手自...

laravel利用websocket搭建一个简单的实时聊天系统

laravel利用websocket搭建一个简单的实时聊天系统

主要实现功能就是用户之间的的实时聊天。理一下业务逻辑:用户A给用户B发送消息>如果用户B在线,直接通过websocket推送消息,用户B接受到消息后写入前端数据库,并归档数据>如果用户B不...

workerman中捕获notice错误并抛出异常

在workerman中出现了notice错误并不会中断程序运行,这是抛出一个无关紧要的提示,这显然与我们的程序设计初衷不符。例如我们去获取数组中的一个key-value值,当key不存在的时候只是提示...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。