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.onSocketMessage
API来接收服务器的消息事件
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
著作权归作者所有,转载请联系作者获得授权,切勿私自转载。