WePY+WebSocket实现聊天小程序

2021-01-08 10:12发布

socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。可以用来实现不同虚拟机或不同计算机之间的通信。网络上的两个程序通过一个双线的通信连接实现数据的交换,这个连接的一端称为一个socket。关于这一点 属于网络协议部分内容,想深入了解此部分的请移步专栏:

笑谈网络协议


WebSocket是基于TCP的一种新的网络协议,它实现了浏览器与服务器全双工通信 —— 允许服务器主动发信息给客户端。
和HTTP的Request请求不同,在实现websocket连接的过程中,浏览器需要发出websocket连接请求,然后服务器做出回应,这个过程也就是常说的“握手”。

在websocket API中,浏览器和服务器只需要做一个握手的动作,然后浏览器和服务器之间就形成了一条快速通道。

websocket一般用在“客户端和服务器端交互紧密并且极度频繁”的场景下(比如:端对端的聊天和网络游戏)。打通两者之间的数据通路,而不用定时一次次地发起普通http请求(轮询)。

//启动一个socket代码(客户端)
wx.connectSocket({
	//连接一个socket
	url:'wss://example.qq.com',
	data:{},
	header:{
		'content-type':'application/json'
	},
	protocols:['protocol1'],
	method:'GET'
})

表面上看,和普通请求很像,但它的不凡之处就在于:该请求成功连接一个socket以后,将会保持这个连接的状态,而普通的get/post等请求则是随着http的断开而断开。

这时候,可以调用wx.onSocketOpen这个API监听websocket连接打开事件:

wx.onSocketOpen(function(res){
	console.log('WebSocket连接已打开!');
})

当一个socket打开以后,最重要的内容则是通过该socket发送一个需要的信息——这需要用到API:wx.sendSocketMessage;当然,这个“发送”必须在“打开”(的回调success)之后(WePY中是在then之后):

wx.onSocketOpen(function(res){
	wx.sendSocketMessage({
		data:msg
	})
})

(不过实际中并不这样写,在页面Load中init“Open”,open中取receive,这个send反而是放在具体监听的事件中调用)

既然发送出去了,就得接受服务器端的消息(不然怎么“对话”啊~):在打开socket之后,可以调用wx.onSocketMessageAPI来接收服务器的消息事件

wx.onSocketMessage(function(res){
	console.log('收到服务器的消息:'+res.data)
})

而在消息的发送和接收过程中,因为某些原因出现一些错误是不可避免的——比如客户端设备无法打开socket、或者网络掉线/延迟、或者服务端请求过多造成拥堵…
这时就需要“手动”提示开发者或用户了:

wx.onSocketError(function(res){
	console.log('websocket连接打开失败,请检查系统及网络!');
})

最后,我们完成了一个socket连接,用户却不用了,那就要及时断开 —— 一个服务器接收和承载连接数是有限的,及时地断开不需要的链接可以极大地减轻服务器的压力,减少资源的浪费:

wx.onSocketClose(function(res){
	console.log('websocket连接已关闭!');
})

我们将上面的知识点总结一下:
实战:简单的socket聊天室小程序
后端:node.js

npm install -g ws 1

全局安装websocket用到的npm包。

安装完成后,在项目中新建一个server.js文件:

const WebsocketServer=require('ws').Server;
let wbsocketServer=new WebsocketServer({
	port:8081,
	autoAcceptConnections:true
})

let clients=[]
let connectNum=0
//监听连接和消息
wbsocketServer.on('connection',(ws)=>{
	clients.push(ws);
	++connectNum;
	console.log('连接的数量:'+connectNum);

	ws.on('message',(message)=>{
		let objMessage=JSON.parse(message);
		console.log(objMessage.data);
		//可以做一些处理或者转发其它客户端
		
	})
	//随机发送消息
	setInterval(()=>{
		if(connectNum!==0){
			setTimeout(()=>{
				//从连接池中获取最新连接
				clients[clients.length-1].send(JSON.stringify({data:'来自服务器的消息'}))
			},Math.random()*1000*3)
		}else{
			console.log('无客户端连接')
		}
	},10000)
	
	ws.on('close',()=>{
		console.log('有连接断开');
		//删除不需要的连接——一般是“最老的”一条数据
		clients.pop();
		--connectNum;
	})
})

完后就可以用nodemon server.js命令启动服务器。

小程序中开发时一定要勾选“未校验合法域名…”这一项

客户端开发——WePY

npm install wepy-cli -g

wepy init standard chat
--创建了一个chat项目,完成基本配置后,进入该目录

npm i

--生成、监控小程序
wepy build -watch

在app.wpy文件的config配置中新增一个chat页面,并且开启promisify,并且在pages文件夹下创建chat.wpy文件。修改如下所示:

//开启promisify
constructor{
	super();
	this.use('requestfix');
	this.use('promisify');
}
pages:[
	'pages/chat'
],

同一般的微信小程序的<block></block>,我们可以用一个数组存储对话,而使用<repeat></repeat>循环显示聊天内容。
chat.wpy -> template

<template>
	<view class="page">
		<view class="chats">
			<repeat for="{{chats}}" item="item">
				<view style="font-size:20rpx;color:#ababab">{{item.item}}</view>
				<view style="font-size:25rpx;padding-bottom:20rpx;">{{item.text}}</view>
			</repeat>
		</view>
		<view class="chatInput">
			<input placeholder="请输入聊天内容" bindinput="userSay" />
		</view>
		<button @tap="sendMessage" size="mini" class="btn">发送消息</button>
	</view>
</template>

chat.wpy -> style

<style>
.page{
position:fixed;
height:100vh;
width:100vw;
background:#e8e9d2;
}
.chats{
text-align:center;
margin:10vh 10vh 10vw 10vw;
height:65vh;
width:80vw;
background-color:aliceblue;
overflow:auto;
}
.chatInput{
background:aliceblue;
height:40rpx;
font-size:20rpx;
padding:10rpx;
width:70vw;
margin-left:15vw;
border-radius:20rpx;
margin-bottom:3vh;
}
.btn{
width:70vw;
mnargin-left:15vw;
}
</style>

chat.wpy -> js/script

<script>
	import wepy from 'wepy'
	//监听是否打开的状态量
	let socketOpen=false
	export default class chat extends wepy.page{   //wepy中的固定格式
		data={
			say:'',
			chats:[
				{time:'聊天开始',text:''}
			]
		}
		methods={
			//用户输入相关
			userSay(e){
				this.say=e.detail.value
				this.$apply()
			},
			//发送对话
			sendMessage(){
				let time=new Date()
				this.chats=this.chats.concat([time:time.toLocaleTimeString(),text:'我说:'+this.say])
				this.handleSendMessage()
				this.$apply()
			}
		}
		//启动一个socket
		startSocket(){
			wepy.connectSocket({
				url:'ws://127.0.0.1:8081'
			})
		}
		wssInit(){
			const that=this
			this.startSocket()
			//连接失败显示
			wepy.onSocketError(function(res){
				socketOpen=false
				console.log('websocket连接打开失败,请检查!',res)
				setTimeout(()=>{
					that.startSocket()
				},2000)
			})
			//监听连接成功
			wepy.onSocketOpen(function(res){
				socketOpen=true
				console.log('websocket连接已打开')
				//接收服务器的消息
				that.receiveMessage()
			})
		}
		receiveMessage(){
			const that=this
			if(socketOpen){
				console.log('读取socket服务器...')
				wepy.onSocketMessage(function(res){
					let time=new Date()
					let resData=JSON.parse(res.data)
					if(resData.data){
						that.chats=that.chats.concat([{time:time.toLocaleTimeString(),text:'服务器说:'+resData.data}])
						that.$apply()
					}
				})
			}else{
				//未打开状态需要延时重新连接
				console.log('服务器没有连接上')
				setTimeout(()=>{
					that.receiveMessage()
				},2000)
			}
		}
		//发送消息
		handleSendMessage(){
			const that=this
			wepy.sendSocketMessage({
				data:JSON.stringify({data:that.say})
			})
		}
		events={}

		onLoad(){
			const that=this
			setTimeout(()=>{
				that.wssInit()
			},1000)
		}
	}
</script>

wepy是微信小程序中的一个框架,它集合了vue的优势。
故而上述js代码中操作data数据时直接this.xxx而不是this.data.xxx



作者:行舟客

链接:https://yunxiaomeng.blog.csdn.net/article/details/103571435

来源:CSDN
著作权归作者所有,转载请联系作者获得授权,切勿私自转载。