一、什么是websocket:
- WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)
- 它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的
- Websocket是一个持久化的协议
二、websocket的原理:
websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信
在websocket出现之前,web交互一般是基于http协议的短连接或者长连接
websocket是一种全新的协议,不属于http无状态协议,协议名为"ws"
三、websocket与http的关系
相同点:
- 都是基于tcp的,都是可靠性传输协议
- 都是应用层协议
不同点:
- WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
- HTTP是单向的
- WebSocket是需要浏览器和服务器握手进行建立连接的
- 而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接
联系:
- WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的
总结(总体过程):
- 首先,客户端发起http请求,经过3次握手后,建立起TCP连接;http请求里存放WebSocket支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version等;
- 然后,服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据;
- 最后,客户端收到连接成功的消息后,开始借助于TCP传输信道进行全双工通信。
四、具体实现websocket聊天功能
1、服务端连接websocket,可参考官方文档
WebSocket服务器 | Swoole4 文档
<?php //创建WebSocket Server对象,监听0.0.0.0:9502端口
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9501);//连接redis
$redis = new Redis();
$redis->connect("127.0.0.1",6379);
$redis->auth('123456');//监听WebSocket连接打开事件
$ws->on('Open', function ($ws, $request) {echo $request->fd. "连接上了\n";
});//监听WebSocket消息事件
$ws->on('Message', function ($ws, $frame) use ($redis) {$params = json_decode($frame->data,true);print_r($params);switch ($params['type']) {//判断是谁发的消息case 'open':$redis->set($params['who'],$frame->fd);break;//判断给谁发case 'send':$to = $redis->get($params['to']);$ws->push($to,json_encode($params['msg'],true));break;case 'active':echo "这是心跳检测\n";break;default:break;}});//监听WebSocket连接关闭事件
$ws->on('Close', function ($ws, $fd) {echo "client-{$fd} is closed\n";
});$ws->start();?>
2、微信小程序端样式
<view><view class="chat"><view wx:for="{{list}}" wx:key="list"><view class="service" wx:if="{{item.who=='service'}}"><text>{{item.msg}}</text></view><view class="client" wx:else=""><text>{{item.msg}}</text></view></view></view><view class="send"><input type="text" value="{{inputVal}}" bindblur="sendMsg" placeholder="请输入内容" /></view>
</view>
3、给页面添加样式
.chat{width: 400px;height: 600px;
}.send{width: 400px;height: 50px;
}.service{width: 390px;height: 40px;text-align: left;line-height: 40px;background-color: pink;
}.client{width: 390px;height: 40px;line-height: 40px;text-align: right;background-color: aqua;
}
4、初始化socket连接
function chat() {return new Promise(function () {wx.connectSocket({url: 'ws://ws.xxxxx.com',header: {'content-type': 'application/json'},success: (res) => {console.log("连接成功");},fail: (err) => {console.log("连接失败");}})})
}
5、心跳检测判断是否处于连接状态
function webSocketXin(time = 60000, status = true) {return new Promise(function () {let timing;if (status == true) {timing = setInterval(function () {console.log("心跳已连接");wx.sendSocketMessage({data: JSON.stringify({'type': 'active'}),fail: (res) => {clearInterval(timing);console.log("心跳已关闭");}})}, time)} else {clearInterval(timing);console.log("心跳已断开");}})
}
6、初始化页面信息
import ws from "../../untils/ws"Page({/*** 页面的初始数据*/data: {inputVal: "",list: [{"who": "service","msg": "很高兴为您服务。"}, {"who": "client","msg": "你好"}]},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {ws.chat(); //初始化连接ws.webSocketXin(60000, true); //心跳检测wx.onSocketOpen((result) => {let message = {who:'client',to:"service",type:'open',}wx.sendSocketMessage({data: JSON.stringify(message),})})wx.onSocketMessage((res)=>{console.log(res.data);let result = JSON.parse(res.data);let list = this.data.list;let msg = {who:"service",msg:result,}list.push(msg)this.setData({list:list})}) },//发消息sendMsg(e) {let inputVal = e.detail.value;let that = this;let list = this.data.list;let message = {who:'client',to:"service",msg: inputVal,type:'send'}wx.sendSocketMessage({data: JSON.stringify(message),success: (res) => {ws.webSocketXin(40000, false)}})list.push(message)inputVal = "";that.setData({list,inputVal})},})