还记得在我毕业面试时,经常看到碰到的面试题中都有着TCP中的keep-alive和Http中的keep-alive有什么区别。但是现在的八股文中已经再也见不到了(燕子,我们还会再见吗)
话说回来,这两个不同的协议中,keep-alive分别代表什么意思呢?
TCP中的keep-alive
我们先来看看TCP协议的报文格式长什么样的先,具体格式文档:https://datatracker.ietf.org/doc/html/rfc9293
能看到,在报文格式中并没有keep-alive这个属性或参数。但是在文档中数据传输那一节中,说明了keep-alive的作用:
TCP中的keep-alive是操作系统对于TCP协议的一种附加功能,用于检测本条TCP连接的状态。但这个附件功能并不是TCP协议中强制要求实现的部分,而且keep-alive功能在TCP中是默认关闭的。
keep-alive会在TCP连接空闲时间到达某个阈值时,开启keep-alive一方会向另一方发送一个空的数据包,如果另一方在多次发送空数据包均无响应后,TCP则会通知应用层连接失效。
简单来说,TCP中的keep-alive是一种由操作系统实现的连接检测机制,但该机制检测出来的异常连接并非一定准确,在TCP文档中着重介绍了这一点。
简单示例
在Windows中变更keep-alive探测时间需要修改注册表,路径:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
对应有几个参数:
参数 | 描述 | 默认值 | 单位 |
---|---|---|---|
KeepAliveTime | TCP空闲触发时间 | 7200000 2小时 | 毫秒 |
KeepAliveInterval | 没有收到探测包响应时,重新发送keep-alive探测包的间隔时间 | 1000 | 毫秒 |
TcpMaxDataRetransmissions | 重试次数 | 5 | 次数 |
为了便于测试,我将触发时间缩短成50秒。
需要显示声明使用keep-alive,否则该功能不会开启。
测试服务端:
public class ServerMain {public static void main(String[] args) throws IOException, InterruptedException {try (ServerSocket serverSocket = new ServerSocket(18888)) {Socket accept = serverSocket.accept();accept.setKeepAlive(true);System.out.println("客户端已连接!");Thread.sleep(1000000000L);}}
}
测试客户端:
public class ClientMain {public static void main(String[] args) throws IOException, InterruptedException {Socket socket = new Socket("127.0.0.1", 18888);System.out.println("client connected");Thread.sleep(10 * 60 * 1000);}
}
使用Wireshark进行抓包后,可以看到在TCP连接后的50秒后,发送了keep-alive的探测包,并且每隔50秒都会进行发送。
这就是TCP中keep-alive的作用,监测并维持空闲TCP连接。
HTTP中的keep-alive
在HTTP1.0中就已经有keep-alive
的请求头了,但这个请求头只是部分服务器支持,并且也不在协议的标准之内。于是,在HTTP1.1中则新开了一个章节,着重说明了keep-alive
请求头的作用。
https://datatracker.ietf.org/doc/html/rfc2068#section-19.7.1
在协议中,说明了当Connection
请求头为keep-alive
时,客户端以及服务器都需要复用本条TCP连接。
浏览器中无法显式关闭keep-alive(想关也不给你关😢),只能在服务器中通过控制keep-alive参数进行关闭,例如tomcat的maxKeepAliveRequests
。关闭之后,可以从控制台中,看到关闭前,只需要第一次请求需要连接服务器,其余请求无需再次连接服务器,正是连接复用的作用。
关闭之后,每次请求都需要跟服务器进行连接,虽然时间也不长,但是也会消耗服务器资源的。在响应头中也能看到Connection
为close
。
总结
差异点 | TCP | HTTP |
---|---|---|
定义 | 操作系统在TCP协议上添加的连接检测机制,用于检测连接状态 | HTTP请求头中的字段,表示复用同一条TCP连接 |
功能 | 检测TCP连接是否仍然有效,通过空闲时发送探测包来验证连接状态 | 允许在同一TCP连接上发送多个HTTP请求,减少连接建立的开销 |
是否为协议标准 | 不是TCP协议的强制标准,且默认关闭 | 协议的标准,默认开启 |
题外话-时代的落幕
1996年5月HTTP1.0协议正式发布,第二年HTTP1.1随之发布。但是HTTP2.0却是在2015年5月才正式发布,并且2.0还是基于Google2009年11月份发布的实验性SPDY协议**。**
那为什么Google要发布SPDY协议呢,归根结底,还是由于HTTP1.1在当时已经不满足于愈发发展的互联网了。最经典的例子,HTTP1.1在请求时会阻塞当前TCP连接,在请求数少时还能接受,当请求数高的时候,延迟就十分严重了。
现在我们在请求一个网站的时候,按下F12可以看到在请求的协议中,大部分都已经是HTTP2了。协议的升级不仅使我们访问网页的速度变快,同时也说明了时代的变革了。
SPDY协议的推出:https://blog.chromium.org/2009/11/2x-faster-web.html
使用 SPDY 和 HTTP/2 提高 Web 速度:https://blog.chromium.org/2013/11/making-web-faster-with-spdy-and-http2.html
Chromium优先先使用HTTP2.0进行连接:https://blog.chromium.org/2015/02/hello-http2-goodbye-spdy.html
TCP虽然没有像HTTP协议一样发布了多个版本,但是也一直进行着多次改进。传输层协议也推出了很多新的协议,最出名的就是HTTP3使用的GoogleQUIC
协议,以及特斯拉最新发布的TTPOE
。
TTPOE:https://www.servethehome.com/tesla-dojo-exa-scale-lossy-ai-network-using-the-tesla-transport-protocol-over-ethernet-ttpoe/