博客建起来的第二天,总想着要写些什么东西。刚好最近在公司做的项目有关于websocket的一些功能。遂借着这次机会,把自己知道的东西好好的梳理一下。
1、Websocket 概述
1.1 websocket 是为何诞生的?
作为一名做web开发的工程师,我们总会碰到,总会出现一些需求。比如:
- 用户购买完商品后。需要对用户商品的物流信息做及时推送
- 炒股软件中股价的实时变动
- 游戏或这体育赛事的事件变动
这些功能中,信息变动是的时间是不固定的,它们随时都有可能变动。在传统的基于http协议开发流程中,我们知道,http协议是无状态的,服务端并不会保存客户端的状态。它总是被动接受请求,然后做出响应。于是给出的解决方案一般都是,基于前端页面的ajax轮循请求。通过定时请求,保证了页面数据的“自动”更新的功能。
但是就算如此数据也还是没有达到“即时”通知的效果,数据更新的过程中,最差的延迟情况就是定时请求刷新的时间长度。
那有人会说:我们可以设置1秒请求一次,这样就保证的减少了数据的延迟时间。但这样服务器端的压力也就大了许多。并且每次请求到要建立连接,都要做tcp三次握手(当然可以通过添加请求头 Connection: keep-alive的方式优化)。这样就无端浪费了很多计算资源。
于是有人就想:为什么不能有一种协议,请求建立后保持连接,让服务器主动发送消息。于是websocket就就出现了
1.2 什么是websocket?
以下参照百度百科的介绍:
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket允许服务端主动向客户端推送数据。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
1.2.1、报文分析
Websocket的请求是基于http协议升级而来的。我们来看看二者的请求报文
HTTP请求:
1 | # 请求 |
Websocket请求:
1 | GET ws://example.com/ws HTTP/1.1 |
通过对比我们发现 websocket 请求多了以下几个字段
1 | Connection: Upgrade #我要升级协议 |
注意:
- websocket 必须是get请求且协议版本不小于1.1
- 必须包括”Sec-WebSocket-Key”头域,其值采用base64编码的随机16字节长的字符序列
那么基于这个请求报文,响应报文如下:
1 | HTTP/1.1 101 Web Socket Protocol Handshake |
Sec-WebSocket-Accept 是必须包括的字段,该字段是由请求报文中Sec-WebSocket-Key的值拼接上 Websocket协议中特殊字符串”258EAFA5-E914-47DA-95CA-C5AB0DC85B11”后,做sha-1加密在base64编码后的一串字符
就此Websocket连接建立完毕。后续连接的保持则是需要”心跳包”机制来作为验证的。
1.2.2、心跳机制
websocket连接完成后,服务器也需要检测对端的连接状态,中途是否断开是否无响应。此时为了检验两端的响应状态,需要在规定时间范围内向对端发送数据,证明双方连接正常。若有一端未在规定时间内接到数据,则判断连接异常断开连接
心跳机制只需要双方定时给对端发送数据集合完成验证,后面将会给出事例代码
2、Websocket 功能实现
由于我是写php的,所以后台websocket功能由swoole来实现
1 |
|
使用 php-cli 运行此脚本开启服务,监听9500端口
sudo php server.php由于服务端设置了心跳机制,所以客户端在保持连接时得定时向服务器发送”心跳包”,表示连接正常.下面是客户端代码:
1 | /** |
打开chart.html在控制台即可看见相关情况
3、总结
以上用swoole简单的实现了一个websocket服务器.配合上消息队列如:rabbitmq, kafka也可以达到推送最新消息的功能.Websocket服务不仅可用于开发聊天室,还能用于开发物联网应用等.
本次后台事例使用了swoole实现,后续会陆续出自己关于swoole的一些理解