Websocket是个啥
WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。
WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455,后由 RFC 7936 补充规范
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据
在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输
简单来说,因为刚开始浏览器端的一整套体系都是基于TCP基础上的http协议的。随着互联网的发展,很多web程序需要建立一个稳定的连接来实现全双工通信。后面发现不管是直接用keep-alive的方法还是polling的方法都很繁琐而且浪费带宽
而浏览器不能直接操作底层的TCP连接,想要实现类似TCP的全双工通信,那么只能给现有的规则打个“补丁”了,再造一个轮子
于是新的基于TCP连接的Websocket协议就应运而生了,浏览器端想要建立一个ws连接的时候,只需要向服务器端发一个HTTP Upgrade 包,就能将自己的连接升级到ws
理论上,这也属于“降级”,把原本http协议剥离的很多TCP特性给加了回来
Real World Practice
例如一个聊天室网站,需要“即时性”保障,不可能使用轮询这种办法了,而keep-alive太耗费带宽而且是单向通道,不符合业务需求
这个时候针对每个用户会话,使用Websocket是比较合适的
Websocket连接之管理
ws是有状态的协议,经过两次握手之后就建立起来了。得益于他是建立在TCP协议之上的,所以他的数据传输可以保证是可靠的,相当于数据流淌在一个可靠的管道中,不受外界影响
但是TCP连接本身是建立在IP上的,只要是套接字实现的通信,就不可能永远存活,有可能因为防火墙,监管,网络超载,甚至物理链路本身损坏而断开
换言之,这个管道可以保障数据正常传输,但是管道这个基础设施本身有坏掉的风险,为了实现真正可靠而且有效的ws链接,我们需要自己实现心跳机制,超时机制这些东西
ws链接本身十分必要,但是管理起来很繁琐,同时也很灵活
参考项目聊天室
花了一段时间参考了这个项目,在这个项目里面构建了一个专用的http协议升级器,只要GET到/ws目录就马上将*gin.context交给websocket升级器处理,输出一个连接的指针,通过这个websocket连接抽象来读取客户端发来的信息和向客户端发送信息
通过这个项目可以从前端自动发送心跳包,服务端得到一个心跳包后立即将其放入“活人池”(允许我这么说hh),记录这个心跳包是什么时候发过来的
构造了一个定时清理死人的cron定时任务,自动将很久没有发送心跳包的连接清除出“活人池”,然后关闭这个ws连接,并广播这个人已经离开的消息
这个项目的缺点
大量使用全局变量,通过一个全局channel来使其在一段时间内只允许一个对连接的写操作。这确实简化了ws的处理,但是容易造成阻塞和延迟,不能算是“最佳实践”