大部分开发者接触 长连接 概念可能都是通过:
HTTP 1.1 版本默认采用长连接,通过头部的
Connection:Keep-Alive实现。
通过TCP/IP协议栈的学习,我们知道HTTP其实是基于TCP的应用层协议。实际上HTTP是无状态协议,所谓无状态,就是HTTP一个请求对应一次响应,如果不做一点特殊的操作,服务器不可能知道客户端上一次请求的状态。HTTP 1.1版本使用的Keep-Alive是服务器使用超时策略维护相应的TCP连接,当链路空闲,服务器很快就会断开连接。
概念
短连接:每一次客户端请求-服务端响应的过程都需要建立一个新的连接,也就是说每一次连接都需要经过完整的TCP三次握手、四次挥手。
长连接:一次连接建立,多次使用;也就是说多次连接只需要一轮最开始的三次握手、到连接结束/失效的四次挥手操作。
长轮询:客户端发送请求,服务器不立马响应,而是保持当前连接,直到有数据时才返回。
实际上的长连接、短连接都是TCP层面的概念
使用场景
长连接多用于操作频繁,连接数不太多的情况,如:点对点通讯、数据库连接等,优势是不用每次数据传输都进行繁琐的连接建立过程,坏处是每一个连接的维持都需要耗费服务器的资源:句柄、服务端线程等,如果连接数过多,可能造成服务器资源耗费严重,所以服务器通常会指定允许客户端最大连接数防止这种现象发生。
短连接则相反,用于并发量大,但操作没有那么频繁的场景
TCP长连接
TCP连接建立后,服务器如何知道某个客户端连接是否还有效?如果一个连接在使用一次之后就不再继续发送数据了,那么服务器完全没有必要继续保持这个连接。而如果没有一定的检测机制,服务器是无法知道到底哪些连接还需要继续保留,哪些连接是需要废弃的;这种检测机制称为连接保活,可以通过内置的KeepAlive机制或者自定义心跳策略实现。
KeepAlive机制
TCP服务器可以开启SO_KEEPALIVE选项来启用KeepAlive机制,默认的超时时间为2小时,探测次数为5次。需要说明的是:
keepalive并不是TCP规范的一部分。在Host Requirements RFC罗列有不使用它的三个理由:(1)在短暂的故障期间,它们可能引起一个良好连接(good connection)被释放(dropped),(2)它们消费了不必要的宽带,(3)在以数据包计费的互联网上它们(额外)花费金钱。然而,在许多的实现中提供了存活定时器。
工作原理:如果某个连接在两小时内没有任何操作,服务器会向客户端发送一个探测报文段,此时客户端可能是下列四种状态之一:
- 客户端正常响应,则重置存活定时器
- 客户端崩溃导致无法响应,服务器在无法收到响应的情况下,75秒后重发探测报文段,持续10次,如果最终无法获取客户端响应,则终止连接
- 客户端可以响应,但已经不是原来的连接(客户端故障重启),此时客户端返回连接重置信号导致服务器终止本次连接
- 客户端正常,但是由于网络原因无法通信,服务器无法区别其与第二种情况,连接终止
心跳机制
也可以称为ping/pong机制,在自定义TCP服务器比较常见,通常是在服务器闲时为了应对下一次爆发增长的请求(需要在单位时间建立连接,这是很耗时/耗资源的)而采取的机制。有时候还可能在心跳包中携带必要/重要的信息,当然这取决于怎么设计,通常心跳间隔时间较短。
工作原理:针对一段时间内没有任何数据发送的连接,服务器定时向其发送一个数据包(通常没有具体意义),客户端如果正常接收则返回一个特定的响应信息,表明本连接还有效。如果服务器一定时间内未接收到响应,则会启用重发机制,在重发阶段内如果客户端正确响应则继续保持连接,否则会终止连接,若实现了自动重连机制则启用一定策略重新建立本次连接。
WebSocket协议
在WebSocket协议出现以前,HTTP协议下如果要实现真正的“长连接”(所谓的全双工,服务器可以主动给客户端发送消息),只能通过轮询、长轮询的方式请求服务器获取响应。
WebSocket的出现就是为了解决客户端与服务器的实时通信问题:
WebSocket是基于TCP的新的通信协议,实现了浏览器与服务器全双工通信-允许服务器主动发送消息给客户端。该协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。
连接建立过程
实现WebSocket连接需要基于HTTP的“握手”进行协议 升级 :
浏览器在HTTP请求头中携带:
Upgrade: websocket; Connection: Upgrade;表示希望将HTTP协议升级到WebSocket协议
服务器响应:
HTTP 1.1 101 Switching Protocols Upgrade: websocket; Connection: Upgrade;告诉浏览器即将升级的是WebSocket协议