1.什么是长连接?
什么是长连接?这里指的是WebSocket,一种应用层持久化的协议。是由HTTP5规范提出的一种协议。
HTML5 Web Sockets规范定义了Web Sockets API,支持页面使用Web Socket协议与远程主机进行全双工的通信。它引入了WebSocket接口并且定义了一个全双工的通信通道,通过一个单一的套接字在Web上进行操作。HTML5 Web Sockets以最小的开销高效地提供了Web连接。这就极大的减少了不必要的网络流量与延迟。该规范定义了ws://以及wss://模式来分别表示WebSocket和安全WebSocket连接,这就跟http:// 以及https:// 的区别是差不多的。
为什么要有长连接?顺从于时代的发展,消息汇总,产出的发展,人们对于实时类消息的需求越来越高。而HTTP的长连接既消耗大又效果不好,WebSocket主要解决的就是消息的实时传递,得益于它的全双工的通信,低耗的网络消耗。
2.Websocket与HTTP
提起Websocket就离不开和它的前辈HTTP的比较。HTTP协议,各位大佬都很熟悉,我就不献丑了。在此,只简单的介绍与Websocket有关系的我知道的知识点。
HTTP,是一种非持久性应用层的基于TCP/IP的通信协议,连接的建立结束是基于三次握手和四次挥手。作为一个经历一次Request和Response就会关闭的连接来说,实时的需求是一个巨大的挑战,由此,HTTP提出了两种解决方案,一种是ajax轮询,一种是Long poll。但是这两种解决方案,基于HTTP的被动性和HTTP的无状态性。都使得服务资源和网络带宽的大量浪费。是在称不上是一种好的解决方案。
WebSocket则是一种持久性应用层的基于TCP/IP的通信协议。连接的建立和结束也是基于三次握手和四次挥手。甚至在连接建立的起始,是通过HTTP协议建立的连接,然后才会升级为WebSocket协议进行通信。成为TCP连接。WebSockt最大的优点在于
1.连接的不断开,双方保持心跳检测,可以一直保持,直到一方结束通信或心跳失联。
2.服务器的主动推送,连接建立后,服务端可主动推送消息给客户端。每一次消息推送也不必带着头信息,也极大的节省了网络带宽。且连接的断开。也可由服务端主动断开
长连接的建立起始于客户端主动向服务端发起建立连接的请求,并在请求头里添加使用的协议。如下
服务器在接收到请求时,也会借鉴HTTP的三次握手,先建立一个HTTP连接,随后会升级(升级方式包括两种,一种是轮询升级,一种是直接升级。此处有坑。)为Websocket连接。升级完成,就没有HTTP什么事了。此后,双方保持心跳连接,当一方心跳超时后,累积达到超时上限,客户端会主动尝试重连服务端。重试失败或主动断开,都会终止WebSocket连接。不同的是,服务端或客户端主动断开时,也会经历四次挥手的过程。
3.长连接小试DEMO
此处使用的WebSocket框架是在git上开源的基于netty的消息推送的netty-socketio框架。
4.长连接 DEMO浅析
在服务端这边,主要包含配置类,服务端主要类,命名空间类,客户端主要类等类。
在此,只看Websocket的相关文件,关于socketio的长轮询降级类及netty类不介绍,因为我不懂。
1.Configuration:服务端配置类,包含了心跳超时,连接的IP,端口号等等信息的配置。
2.SocketIOServer:服务端类。继承于ClientListeners。参数有 配置文件配置服务端及内部的命名空间,也可以添加不同事件的监听动作
3.NamespacesHub:存放客户端连接的命名空间类,可将不同的客户端存放在不同的房间里,方便不同消息的推送。
4.NamespaceClient:客户端类。保存客户端信息及UUID等信息和发送信息离开房间等动作
5.长连接遇坑记录
以前,基于一个需求,需要WebSocket落地实践,在落地过程中。服务端与客户端中间要通过Nginx作为代理,问题就出在Nginx的请求分发上。
问题:客户端尝试建立长连接,三回里有两回,会建立失败。检查服务器配置,并没有建立连接的请求。
配置:两台Nginx服务器,三台WebSocket服务器
排查:尝试直连WebSocket服务器 ,发现都能正常建立连接,怀疑问题出在Nginx配置上,检查长连接的配置,发现并没有问题。查询资料,研究从HTTP连接升级到WebSocket连接的过程,发现客户端有两种升级方式,一种是直接升级为WebSocket,另一种是通过轮询请求升级。而默认的是通过轮询请求升级。问题就出在这,当通过Nginx分发请求时,轮询的请求会被分发。导致升级失败。
结果:最后客户端修改升级方式为WebSocket就可以了。
6.对长连接的思考
由于HTTP,WebSocket都是对TCP的应用层实现协议,所以底层的连接建立都是TCP的经典建立要素:IP+端口号+传输层协议
也就是说。当客户端IP+客户端端口+服务端IP+服务端端口+传输层协议(TCP)。才会确定一个连接
换句话说 服务端IP+服务端端口 在建立一个连接时,只能是WebSocket或者HTTP。而WebSocket会长时间占据一个端口号。可服务器可开最多的端口号毕竟是有效的。长时间多用户的WebSocket会把服务器的端口号全部消耗掉。而且如果时Nginx,这个消耗量将会是Double。目前,这个问题也困扰着我。WebSocket是怎么解决端口号数量局限性的问题?