讲解长连接前,需要先了解短链接的原理,以及存在的问题
HTTP/1.0短链接
HTTP/1.0短链接机制
HTTP/1.0默认采用短链接,工作流程如下:
-
**客户端发起连接请求:**客户端与服务端建立TCP连接(三次握手)
-
**发起HTTP请求:**哭护短通过已建立的TCP连接发送HTTP请求报文
-
**服务器处理请求:**服务器接收到请求,处理并生成HTTP响应报文
-
**发起HTTP响应:**服务器通过同一个TCP连接发送响应报文给客户端
-
关闭TCP连接: 服务器或客户端在发送完响应或接受完响应后,立即关闭TCP连接(四次挥手)
-
**重复上述步骤:**如果客户端需要获取更多资源,它必须重复上述所有步骤,重新建立TCP连接
短链接性能瓶颈
-
TCP连接建立和关闭的开销
-
**三次握手:**每次建立TCP连接都需要客户端和服务端之间进行三次报文交互,一定程度上会带来网络消耗,同时连接的建立也需要消耗时间
-
**四次挥手:**同样,关闭TCP连接也需要多次报文交互,消耗时间
-
**慢启动:**TCP协议为避免网络阻塞,在建立连接初期会限制发送速率,导致一开始网络传输速率较慢,无法充分利用带宽
慢启动原理详见另一篇博客:TCP如何实现流量控制-CSDN博客
-
-
服务器资源消耗
- 每次建立和关闭连接,服务器都需要频繁进行套接字(socket)的创建和销毁,这会消耗大量CPU和内存资源
-
带宽利用率低下
- 受连接频繁建立和关闭,以及慢启动的影响,TCP连接很难达到最大吞吐量,导致带宽利用率不高
这些问题最终会导致网页加载缓慢,用户体验差
HTTP/1.1长连接
长连接指在客户端和服务端建立一个TCP连接后,连接在完成一次请求后并不会立即关闭,而是保证开放状态,等待后续的HTTP请求。
长连接原理
-
**客户端发起请求:**客户端与服务器建立TCP连接(三次握手)
-
**发送HTTP请求:**客户端发送HTTP请求报文
-
服务器处理与响应: 服务器处理请求,发送HTTP响应报文
-
**TCP连接保持开放:**服务器在发送完响应之后,不会立即关闭TCP连接,而是通过协商好的超时时间和最大请求数,保持连接开放
-
**后续请求和复用连接:**客户端在需要获取其他资源时,可以通过这个已经建立的TCP连接发送新的HTTP请求,无需再进行TCP三次握手
-
**连接关闭:**当客户端或服务端不再需要此链接(达到超时时间、客户端所有资源已获取,服务器资源限制等),会发起关闭TCP连接请求(四次挥手)
如何启用长连接
Connection:keep-alive
在HTTP/1.1中,长连接是默认的,客户端和服务器之间通过HTTP请求头 中包含的Connection:keep-alive来显式地协商是否保持连接,虽然HTTP/1.1规范中规定长连接是默认开启的,但为了兼容老旧客户端或代理,或者在某些特殊场景下,仍然会看到这个头部。
-
客户端请求头
GET /index.html HTTP/1.1 Host: www.example.com Connection: keep-alive -
服务器响应头
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 1234 Connection: keep-alive Keep-Alive: timeout=5, max=100服务器响应头中的
Keep-Alive字段提供了详细的连接管理信息:-
timeout:指定服务器保持连接的秒数,如果在指定时间内没有接收到新的请求,服务器将关闭连接 -
max:指定此次连接上允许发送的最大请求数量,到达此数量后,服务器关闭连接
-
如何关闭长连接
-
显式关闭
-
客户端或服务器发送
Connection: close头部 -
任何一方都可以主动决定关闭连接
-
-
超时关闭
服务器可以通过
Keep-Alive头部设置超时时间和最大请求数,比如 `Keep-Alive: timeout=5, max=1000` 这表示连接在空闲5秒后会被关闭,或者最多处理1000个请求后关闭 -
错误或意外关闭
-
TCP连接本身出现错误、超时或中断
-
一方意外崩溃
-
长连接优势
-
减少延迟:
-
避免频繁三次握手和四次挥手:对于后续请求,不需要重新建立连接
-
**减少TCP慢启动影响:**TCP连接刚建立时,会有一个慢启动过程,限制发送速率,之后再慢慢提高发送速率,复用连接可以避免多次慢启动,保持较大的传输速率
-
-
降低服务器资源消耗:
-
减少服务器频繁创建和销毁套接字的开销,降低服务器CPU和内存压力
-
TCP连接复用意味着服务器不需要进行频繁的状态切换,有助于服务器处理更多并发连接
-
-
提高带宽利用率:
- 连接在较长时间内允许数据传输,能更好利用可用网络带宽
长连接局限性
-
请求的队头阻塞: 在HTTP/1.1中,即使使用了长连接,客户端也必须严格按照请求的顺序发送。也就是说,在一个TCP连接上,客户端发送完第一个请求后,必须等待服务器的响应,才能发送第二个请求。如果第一个请求的处理时间较长,或者传输过程中某个响应丢失,那么后续的所有请求都将被阻塞
-
管道化尝试与失败: HTTP/1.1引入了管道化机制,试图缓解队头阻塞。它允许客户端在收到前一个响应之前,就发送多个请求。服务器也会按顺序处理这些请求并发送响应。然而,管道化在实际应用中遇到了很多问题:
-
服务器响应顺序必须与请求顺序一致: 如果服务器处理第一个请求耗时很长,即使它已经处理完了后续的请求,也必须等待第一个请求的响应发送完成后才能发送。这实际上是将队头阻塞从客户端请求端转移到了服务器响应端。
-
代理和中间件的兼容性问题: 很多老的代理服务器和中间件不支持HTTP管道化,或者实现不完善,导致其普及度非常低。
-
连接断开后的重试复杂性: 如果管道化发送了多个请求,但连接在某个响应返回前断开,客户端很难判断哪些请求已经成功,哪些需要重试,增加了实现的复杂性。
-
由于这些限制,HTTP/1.1最终没有被广泛应用,对头阻塞问题,成为推动HTTP协议进一步演进的重要动力
-