1.1TCP是什么
TCP 是面向连接的、可靠的、基于字节流的
传输层通信协议。
面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;
可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;
字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。
1.2 TCP连接定义
连接:用于保证可靠性和流量控制维护的某些状态信息,这些信息包括 Socket、序列号和窗口大小。
TCP四元组确定唯一的一个连接:源地址、源端口、目的地址、目的端口。
所以一个服务的某个端口,最大TCP连接数=客户端IP数 * 客户端端口数
。IPv4有32位,端口数有16位,理论上最大连接数是2的48次方。
但实际上由于文件描述符限制及内存限制,不能达到此上限。
2. TCP/UDP头格式
2.1 TCP头格式
源端口号/目的端口号
序号
解决包乱序问题确认序列
目的是确认发出去对方是否有收到。如果没有收到就应该重新发送,直到送达,这个是为了解决丢包的问题。首部长度
表示TCP首部有多少个(4字节)的值。状态位
URG ( urgent pointer) :紧急指针,当URG标志位被设置为1时,紧急指针被用来告诉设备发送的数据包的紧急程度。当标志位被设置为0时,紧急指针不产生任何效果。
ACK (acknowledgment):确认,当ACK标志位被设置为1时,确认号字段有效。TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1。
PSH (push):该位为 1 时,接收设备应该立即将这个数据包交给应用程序,而不是缓冲它。
RST (reset):该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
SYN (synchronize):该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
FIN (finish):该位为 1 时,表示今后不会再有数据发送,希望断开连接。
窗口大小
双方都维护一个窗口(缓存大小),标识自己当前能够的处理能力。解决流量控制及拥塞控制问题。校验和
TCP头部和数据部分的校验和,这是一个强制性的字段,由发送端计算和存储,并由接收端进行验证。其主要功能是检查数据在传输过程中是否发生了错误。紧急指针
只在URG位字段被设置时才有效。这个“指针”是一个必须要加到报文段的序列号字段上的正偏移,以产生紧急数据的最后一个字节的序列号。TCP的紧急机制是一种让发送方给另一端提供特殊标志数据的方法。
2.2 UDP头格式
UDP 不提供复杂的控制机制,利用 IP 提供面向「无连接」的通信服务。
目标和源端口:主要是告诉 UDP 协议应该把报文发给哪个进程。
包长度:该字段保存了 UDP 首部的长度跟数据的长度之和。
校验和:校验和是为了提供可靠的 UDP 首部和数据而设计,防止收到在网络传输中受损的 UDP 包。
2.3 TCP和UDP区别
连接
TCP 是面向连接的传输层协议,传输数据前先要建立连接。
UDP 是不需要连接,即刻传输数据。服务对象
TCP 是一对一的两点服务,即一条连接只有两个端点。
UDP 支持一对一、一对多、多对多的交互通信可靠性
TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。
UDP 是尽最大努力交付,不保证可靠交付数据。但是我们可以基于 UDP 传输协议实现一个可靠的传输协议,比如 QUIC 协议,具体可以参见这篇文章:如何基于 UDP 协议实现可靠传输?(opens new window)拥塞控制、流量控制
TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。首部开销
TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的。
UDP 首部只有 8 个字节,并且是固定不变的,开销较小。传输方式
TCP 是流式传输,没有边界,但保证顺序和可靠。
UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。分片不同
TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。
2.4 TCP 和 UDP 应用场景
由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:
FTP 文件传输;
HTTP / HTTPS;
由于 UDP 面向无连接,它可以随时发送数据,再加上 UDP 本身的处理既简单又高效,因此经常用于:包总量较少的通信,如 DNS 、SNMP 等;
视频、音频等多媒体通信;
广播通信;
2.5 TCP 和 UDP 可以使用同一个端口吗
可以,因为 TCP 和 UDP在内核中是两个完全独立的软件模块。而端口号的作用,是为了区分同一个主机上不同应用程序。
2. TCP连接建立
2.1 三次握手过程
第三次握手是可以携带应用层数据的,前两次握手是不可以携带应用层数据的。
2.2 需要三次握手的原因
避免历史连接
同步双方初始序列号
避免资源浪费
2.2.1 避免历史连接
客户端先发送旧SYN(Seq Num=90)发起连接,由于网络问题没有达到,发送新SYN(Seq Num=100)发起另一个连接。(不是重试,重试的Seq Num不会变化)
情况一:服务端接收顺序 旧SYN - RST - 新SYN
#### 情况二:服务端接收顺序 旧SYN - 新SYN - RST 服务端连续收到SYN包时,第二次会回复服务器认为正确的Ack Num(90 + 1),客户端发现不是期望的101,依然会发送RST包。这个响应和已经建立连接的情况下,客户端发送同样ip和端口的SYN包情况相同。
如果是两次就建立连接,类似场景就会导致很多无效历史连接。
2.2.2 同步双方初始序列号
序列号作用:
接收方可以去除重复的数据;
接收方可以根据数据包的序列号按序接收;
可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道)
一来一回,才能确保双方的初始序列号能被可靠的同步。至少需要三步。
2.2.3 避免资源浪费
场景同避免历史连接,如果只有两次会建立很多无效连接,导致资源被浪费。
2.3 三次握手中的某一步包丢失会怎样
客户端SYN包丢失
客户端会超时重发SYN包。
服务器ACK+SYN包丢失
此时客户端已发送SYN包,由于没有收到ACK包确认,故会认为丢失触发超时重传机制。
服务器由于也不会收到客户端的ACK包,也会触发超时重传机制。
客户端ACK包丢失
ACK包不会重传
,所以服务器会一直重试发送ACK+SYN包。
2.4 SYN攻击
攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个 SYN 报文,就进入SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的半连接队列,使得服务端不能为正常用户服务。
在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:
半连接队列:SYN 队列
全连接队列:accept 队列
正常流程:
当服务端接收到客户端的 SYN 报文时,会创建一个半连接的对象,然后将其加入到内核的「 SYN 队列」;
接着发送 SYN + ACK 给客户端,等待客户端回应 ACK 报文;
服务端接收到 ACK 报文后,从「 SYN 队列」取出一个半连接对象,然后创建一个新的连接对象放入到「 Accept 队列」;
应用通过调用 accpet() socket 接口,从「 Accept 队列」取出连接对象。
不管是半连接队列还是全连接队列,都有最大长度限制,超过限制时,默认情况都会丢弃报文。SYN攻击便是利用的这个原理。
3. TCP连接断开
3.1 四次挥手过程
3.2 需要四次挥手的原因
关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
3.3 有没有可能三次挥手
是可能的。服务器「没有数据要发送」并且「开启了 TCP 延迟确认机制」,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。
TCP 延迟确认机制是默认开启的,所以只要服务器「没有数据要发送」就可能出现三次挥手。当发送没有携带数据的ACK,它的网络效率也是很低的,所以出现了TCP 延迟确认机制。
TCP 延迟确认的策略:
当有响应数据要发送时,ACK 会随着响应数据一起立刻发送给对方
当没有响应数据要发送时,ACK 将会延迟一段时间,以等待是否有响应数据可以一起发送
如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会立刻发送 ACK
3.4 为什么 TIME_WAIT 等待的时间是 2MSL
MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。MSL 的单位是时间,而 IP头中TTL 是经过路由跳数。所以 MSL 应该要大于等于 TTL 消耗为 0 的时间,以确保报文已被自然消亡。
TTL 的值一般是 64,Linux 将 MSL 设置为 30 秒,意味着 Linux 认为数据报文经过 64 个路由器的时间不会超过 30 秒,如果超过了,就认为报文已经消失在网络中了。
TIME_WAIT等待2倍的MSL原因:
网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。
比如,如果被动关闭方没有收到断开连接的最后的 ACK 报文,就会触发超时重发 FIN 报文,另一方接收到 FIN 后,会重发 ACK 给被动关闭方, 一来一去正好 2 个 MSL。
3.5 为什么需要 TIME_WAIT 状态
防止历史连接中的数据,被后面相同四元组的连接错误的接收
因为序列号是循环使用的。TIME_WAIT 状态,状态会持续 2MSL 时长,这个时间足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。保证「被动关闭连接」的一方,能被正确的关闭
TIME-WAIT 作用是等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。如果客户端(主动关闭方)最后一次 ACK 报文(第四次挥手)在网络中丢失了,那么按照 TCP 可靠性原则,服务端(被动关闭方)会重发 FIN 报文。客户端在收到服务端重传的 FIN 报文时,TIME_WAIT 状态的等待时间,会重置回 2MSL。
假设没有TIME-WAIT状态,那么当客户端收到服务器的FIN报文时已经CLOSE状态,会回复RST报文强制中止连接,不够优雅。
3.6 服务器出现大量 TIME_WAIT 状态的原因有哪些?
TIME_WAIT 状态是主动关闭连接方才会出现的状态,说明服务器主动断开了很多 TCP 连接。
原因:
HTTP 没有使用长连接
无论哪方未启动长连接,都是服务器端主动断开当前连接。HTTP 长连接超时
HTTP 长连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。但是没有任何数据传输并持续到超时后,服务器会调用回调函数主动断开连接。HTTP 长连接的请求数量达到上限
Web 服务端通常会有个参数,来定义一条 HTTP 长连接上最大能处理的请求数量,当超过最大限制时,就会主动关闭连接。
比如 nginx 的 keepalive_requests 这个参数默认值是 100 ,意味着每个 HTTP 长连接最多只能跑 100 次请求。对于QPS较大的服务,应该将keepalive_requests参数值调大。
3.7 服务器出现大量 CLOSE_WAIT 状态的原因有哪些?
CLOSE_WAIT 状态是「被动关闭方」才会有的状态,而且如果「被动关闭方」没有调用 close 函数关闭连接,那么就无法发出 FIN 报文,从而无法使得 CLOSE_WAIT 状态的连接转变为 LAST_ACK 状态
。
所以,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,说明服务端的程序没有调用 close 函数关闭连接
。
那什么情况会导致服务端的程序没有调用 close 函数关闭连接?这时候通常需要排查代码。
分析一个普通的 TCP 服务端的流程:
创建服务端 socket,bind 绑定端口、listen 监听端口
将服务端 socket 注册到 epoll
epoll_wait 等待连接到来,连接到来时,调用 accpet 获取已连接的 socket
将已连接的 socket 注册到 epoll
epoll_wait 等待事件发生
对方连接关闭时,我方调用 close
可能导致服务端没有调用 close 函数的原因,如下。
第一个原因:第 2 步没有做,没有将服务端 socket 注册到 epoll,这样有新连接到来时,服务端没办法感知这个事件,也就无法获取到已连接的 socket,那服务端自然就没机会对 socket 调用 close 函数了。
不过这种原因发生的概率比较小,这种属于明显的代码逻辑 bug,在前期 read view 阶段就能发现的了。
第二个原因:第 3 步没有做,有新连接到来时没有调用 accpet 获取该连接的 socket,导致当有大量的客户端主动断开了连接,而服务端没机会对这些 socket 调用 close 函数,从而导致服务端出现大量 CLOSE_WAIT 状态的连接。
发生这种情况可能是因为服务端在执行 accpet 函数之前,代码卡在某一个逻辑或者提前抛出了异常。
第三个原因:第 4 步没有做,通过 accpet 获取已连接的 socket 后,没有将其注册到 epoll,导致后续收到 FIN 报文的时候,服务端没办法感知这个事件,那服务端就没机会调用 close 函数了。
发生这种情况可能是因为服务端在将已连接的 socket 注册到 epoll 之前,代码卡在某一个逻辑或者提前抛出了异常。之前看到过别人解决 close_wait 问题的实践文章,感兴趣的可以看看:一次 Netty 代码不健壮导致的大量 CLOSE_WAIT 连接原因分析
第四个原因:第 6 步没有做,当发现客户端关闭连接后,服务端没有执行 close 函数,可能是因为代码漏处理,或者是在执行 close 函数之前,代码卡在某一个逻辑,比如发生死锁等等。
3.8 没有 accept,能建立 TCP 连接吗
可以。
因为accpet 系统调用并不参与 TCP 三次握手过程,它只是负责从 TCP 全连接队列取出一个已经建立连接的 socket。
用户层通过 accpet 系统调用拿到了已经建立连接的 socket,才能对该 socket 进行读写操作。
4. TCP的重传机制/滑动窗口/流量控制/拥塞控制
4.1 重传机制
4.1.1 超时重传
超过指定的时间后,没有收到对方的 ACK 确认应答报文,就会重发该数据。
可能的原因有两种:
数据包丢失,对方未收到
对方已收到,但是ACK报文丢失
RTO值
超时重传时间 RTO (Retransmission Timeout 超时重传时间)的值应该略大于报文往返 RTT(Round-Trip Time 往返时延) 的值。
由于网络环境动态变化,RTO值会通过采样 RTT加权计算的值/RTT波动范围值 动态计算出RTO值。
每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。
4.1.2 快速重传
快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传。当收到三个相同的 ACK 报文时,会在超时重传之前,重传丢失的报文段。
快速重传机制解决了超时重发的时间等待,但是快速重传并不清楚丢失的所有包有哪些
。
比如假设发送方发了 6 个数据,编号的顺序是 Seq1 ~ Seq6 ,但是 Seq2、Seq3 都丢失了,那么接收方在收到 Seq4、Seq5、Seq6 时,都是回复 ACK2 给发送方,但是发送方并不清楚这连续的 ACK2 是接收方收到哪个报文而回复的, 不能一次性精准重传缺失的Seq2、Seq3报文。
4.1.3 SACK
Selective Acknowledgmen,选择性确认。
TCP 头部「选项」字段增加SACK信息,表明已收到的数据包信息。
利用SACK和ACK,发送方可以清楚地知道有哪些包还没收到。SACK机制中,ACK是小于SACK的范围的。ACK到SACK起始位置的数据包表示还没收到,SACK范围内的包表示接收到了。
4.1.4 D-SACK
Duplicate SACK, 使用了 SACK 来告诉「发送方」有哪些数据被重复接收
了。D-SACK机制中,ACK是大于SACK的范围的.SACK范围内的包表示被重复接收了。
4.2 滑动窗口
4.2.1 定义
为了避免通信双方一问一答的低效传输模式,TCP引入了窗口概念。而窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。窗口的实现是操作系统开辟的一个缓存空间
,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。
4.3 流量控制
4.3.1 窗口大小
TCP头部中有窗口大小字段,就是告诉发送端自己还有多少缓冲区可以接收数据
。
发送端就可以根据这个接收端的处理能力来发送数据。如果发送方发送的数据大小超过接收方的窗口大小,接收方就无法正常接收到数据,会导致触发重发机制。
所以发送方的窗口的大小也是由接收方的窗口大小来决定的。如果接收方Window变化了,由于报文有时延,返回的Windows字段要等会儿才会反应到发送方的滑动窗口。所以发送窗口大小约等于接收窗口大小。
4.3.2 滑动窗口流控细节
发送方滑动窗口细节。
每次发送数据后,SND.NXT移动对应长度;收到ACK包确认的序号及窗口大小后,SND.UNA再移动至对应序号及调整窗口大小SND.WND。这样便控制了发送端的发送速率。
4.3.3 窗口关闭
接收方向发送方通告窗口大小时,是通过 ACK 报文来通告的。当发生窗口关闭时,接收方处理完数据后,会向发送方通告一个窗口非 0 的 ACK 报文,告知窗口已开启。
为了避免窗口开启的ACK报文丢失,发送方也有窗口关闭超时机制。超时后,会发送多次窗口探测 ( Window probe ) 报文。如果连续3次窗口依然为0,有的TCP实现会发送RST报文中断连接。
4.3.4 糊涂窗口综合征
糊涂窗口综合征:接口方只有少量字节窗口,发送方依然发送的情况。
避免这种情况,TCP制定了两个策略:
接收方
当「窗口大小」小于 min(MSS,缓存空间/2) ,也就是小于MSS与1/2缓存大小中的最小值时,就会向发送方通告窗口为 0
发送方
Nagle 算法:
窗口大小>=MSS 并且 数据大小>MSS;
等待超时(一般为200ms)
4.4 拥塞控制
流量控制只能控制TCP双方的流量,对于整个网络的拥堵情况却无法感知。
4.4.1 网络拥塞的危害
在网络出现拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 就会重传数据。
但是一重传就会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大。
4.4.2 拥塞窗口算法
拥塞窗口cwnd
控制发送方的发送窗口大小,根据网络的拥塞程度动态变化的,发送窗口=min(拥塞窗口, 接收窗口)
拥塞判断原理
没有在规定时间内接收到 ACK 应答报文,发生了超时重传,就会认为网络出现了拥塞。
拥塞控制算法
慢启动算法
拥塞避免算法
拥塞发生算法
快速恢复算法
4.4.2.1 慢启动算法
TCP 在刚建立连接完成后,首先是有个慢启动的过程。
慢启动规则:当发送方每收到一个新ACK,拥塞窗口 cwnd 的大小就会加 1。
比如连接刚建立吧开始1个,然后2个,然后4个...,,窗口大小呈指数级增长
。
当拥塞窗口达到慢启动门限(ssthresh,slow start threshold,默认65535字节)时,会切换为拥塞避免算法。
4.4.2.2 拥塞避免算法
当拥塞窗口达到慢启动门限(ssthresh,slow start threshold)时,会切换为拥塞避免算法。
拥塞避免规则:每当收到一个新ACK时,拥塞窗口增加1/拥塞窗口。
实际上,就是每秒增加1个,窗口大小呈线性级增长
。
4.4.2.3 拥塞发生算法
当出现数据包重传的情况,便认为拥塞发生了,切换为拥塞发生算法。
针对于超时重传和快速重传,有不同的拥塞发生算法。
针对超时重传的拥塞发生算法
慢启动门限=当前拥塞窗口的1/2,ssthresh=cwnd/2
拥塞窗口=1,cwnd=1
效果就是从慢启动算法重新开始,达到之前拥塞窗口的1/2时便切换为拥塞避免算法了。
针对快速重传的拥塞发生算法
拥塞窗口=当前拥塞窗口的1/2,cwnd=cwnd/2
慢启动门限=更新后的拥塞窗口,ssthresh=cwnd
进入
快速恢复算法
4.4.2.4 快速恢复算法
只有快速重传触发的拥塞发生算法,才会启动快速恢复算法。
拥塞窗口=慢启动门限+3, cwnd=ssthresh+3
重传丢失数据包
收到重复的ACK,拥塞窗口=拥塞窗口+1,cwnd=cwnd+1
收到不重复ACK,拥塞窗口=慢启动门限,cwnd=ssthres
快速恢复算法第3步的算法为什么是这样?
收到重复的ACK,拥塞窗口=拥塞窗口+1
收到重复的ACK表示接收方还没拿到新的数据,网络依然拥塞。
可以看看发送方滑动窗口的图,由于发送方不断的重传丢失的数据包,导致已发送未ACK的范围越来越大,那么可用窗口就会越来越少甚至无法发送。所以拥塞窗口持续+1是一种临时补偿机制。收到不重复ACK,拥塞窗口=慢启动门限
收到重复的ACK表示接收方已成功接收,网络已正常。
此时将拥塞门限重置为慢启动门限,其实是撤销了阻塞期间拥塞窗口持续+1的补偿措施。直接切换到拥塞避免算法。
5. MSS和MTU
既然IP包会按照MTU大小分片,为什么TCP还要提前分片成MSS大小?MTU=IP头部长度+TCP头部长度+MSS
因为IP层是不可靠的,不支持超时和重传机制。
假设没有MSS分片,一个TCP数据包被分成n个IP包,其中一个IP包丢失,那么整个TCP包便不能回复ACK给发送端。超时后,发送端会重新发送整个TCP包,相当于又要重发n个IP包,就算之前收到了n-1个IP包也要重发,效率很低下。
所以,TCP直接根据MTU大小事先按照MSS划分后,就算丢失了一个IP包,也最多重传一个IP包的数据,大大增加了重传的效率。
6. TCP Keepalive 和 HTTP Keep-Alive区别
6.1 TCP Keepalive
TCP Keepalive就是TCP保活机制。
如果两端的 TCP 连接一直没有数据交互,达到了触发 TCP 保活机制的条件,那么内核里的 TCP 协议栈就会发送探测报文。
如果对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。
如果对端主机宕机(
注意不是进程崩溃,进程崩溃后操作系统在回收进程资源的时候,会发送 FIN 报文,而主机宕机则是无法感知的
,所以需要 TCP 保活机制来探测对方是不是发生了主机宕机),或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。
所以,TCP 保活机制可以在双方没有数据交互的情况,通过探测报文,来确定对方的 TCP 连接是否存活,这个工作是在内核完成的。
6.2 HTTP Keep-Alive
HTTP Keep-Alive就是HTTP长连接,使用同一个 TCP 连接来发送和接收多个 HTTP 请求/应答,避免了连接建立和释放的开销。
HTTP请求头和响应头中,都有Connection: Keep-Alive
便可开启长连接。
HTTP 长连接有默认超时时间。如果客户端在长连接超时期间没有再发起新的请求,服务器的定时器的超时时间一到,就会触发回调函数来释放该连接。
6.3 总结
HTTP 的 Keep-Alive 也叫 HTTP 长连接,该功能是由应用程序
实现的,可以使得用同一个 TCP 连接来发送和接收多个 HTTP 请求/应答,减少了 HTTP 短连接带来的多次 TCP 连接建立和释放的开销。
TCP 的 Keepalive 也叫 TCP 保活机制,该功能是由内核
实现的,当客户端和服务端长达一定时间没有进行数据交互时,内核为了确保该连接是否还有效,就会发送探测报文,来检测对方是否还在线,然后来决定是否要关闭该连接。
链接:https://www.cnblogs.com/kiper/p/17899341.html
(版权归原作者所有,侵删)