【Linux-传输层协议TCP】TCP协议段格式+确认应答+超时重传+连接管理机制(三次握手、四次挥手、理解TIME_WAIT + CLOSE_WAIT)
TCP协议
TCP全称为“传输控制协议(Transmission Control Protocol)”人如其名,要对数据的传输进行一个详细的控制。
1.TCP协议段格式
下面是TCP报头各个字段的表格形式:
字段名称 | 字段大小 | 描述 |
---|---|---|
源端口 | 16位 | 发送端TCP端口号。 |
目的端口 | 16位 | 接收端TCP端口号。 |
序列号 | 32位 | 本报文段所发送数据的第一个字节的序列号。 |
确认号 | 32位 | 期望收到对方下一个报文段的第一个数据字节的序列号。若确认号设置为N,则表示到序列号N-1为止的所有数据都已正确接收。 |
数据偏移 | 4位 | TCP头部的长度,以4字节为单位,也指示了选项字段(如果有)的长度。 |
保留 | 6位 | 目前未使用,必须设置为0。 |
控制位 | 6位 | 包括URG、ACK、PSH、RST、SYN、FIN等标志,用于控制TCP连接和传输。 |
窗口大小 | 16位 | 发送方接收窗口的大小,即无需再次确认可以接收的数据量。 |
校验和 | 16位 | 用于校验整个TCP段(包括TCP头部和数据)在传输过程中是否出现错误。 |
紧急指针 | 16位 | 仅当URG标志被设置时有效,指出紧急数据的最后一个字节的序号。 |
选项 | 可变长度 | 可选字段,可以包含多种类型的选项,如MSS、窗口缩放、SACK等。 |
、、、、 | 、、、、、 |
下面是TCP报头中控制位字段的表格形式:
控制位标志 | 占位 | 描述 |
---|---|---|
URG | 1位 | 紧急标志(Urgent)。当URG=1时,表明紧急指针字段有效,指示紧急数据的位置。 |
ACK | 1位 | 确认标志(Acknowledgment)。当ACK=1时,确认号字段有效,表示期望收到对方下一个报文段的第一个数据字节的序列号。 |
PSH | 1位 | 推送标志(Push)。当PSH=1时,要求接收方尽快将数据推送给应用层,而不是等到缓冲区满时才发送。 |
RST | 1位 | 重置标志(Reset)。当RST=1时,表示TCP连接中出现严重错误,需要重置连接。我们把携带RST标识的称为复位报文段 |
SYN | 1位 | 同步序列编号标志(Synchronize)。当SYN=1时,表明这是一个连接请求或连接接受报文。我们把携带SYN标识的称为同步报文段 |
FIN | 1位 | 结束标志(Finish)。当FIN=1时,表明发送方已经发送完所有数据,并要求释放连接。我们把携带FIN标识的称为结束报文段 |
、、、、、 | 、、、 |
这些控制位标志用于TCP连接的建立、维护和终止,以及数据的可靠传输。每个标志都有其特定的作用,通过组合使用这些标志,TCP能够实现复杂的网络通信功能。
4位首部长度
这里有4个比特位,按照正常取值范围就说【0,15】,但是我们的报头至少需要20字节。所以规定TCP报头中4位首部长度的基本单位是4字节,这样取值范围就是【0,60】,所以整个报头大小范围就是【20~60】,报头中选项字段最长为40字节,计算可得,4位首部长度取值范围是【5~15】,转换成二进制就是【0101~1111】
-
TCP如何将报头与有效载荷进行分离?(如何解包的问题)
1️⃣ 读取标准20字节 2️⃣ 提取首部长度 3️⃣ 根据首部长度-20,结果等于0,那就是报头读完,剩下都是数据;如果结果为n(>0),再从报文中提取n个字节,这n个字节对应就是选项的大小,剩下的就是有效载荷了
-
有效载荷如何向上交付?(如何分用的问题)
在计算机网络中,有效载荷(payload)通常指的是数据包中的实际数据部分,不包括头部信息。在TCP协议中,有效载荷是指应用层的数据。有效载荷的向上交付,即从传输层(TCP)交付到应用层的过程
下面是一个简化的表格,展示了有效载荷向上交付和分用的过程:
阶段 | 操作系统内核操作 | 应用层操作 |
---|---|---|
数据接收 | 1. 校验和验证数据段 | - |
2. 检查序列号,重组数据 | - | |
3. 将重组后的数据存入缓冲区 | - | |
数据交付 | 1. 通知应用层有新数据可用 | - |
分用 | 1. 使用端口号匹配对应的套接字 | - |
2. 将数据存入套接字的缓冲区 | - | |
3. 通知拥有套接字的应用进程 | 1. 接收到通知 | |
- | 2. 通过API读取数据 | |
- | 3. 处理接收到的数据 | |
所以说目的端口解决了对报头进行分用的问题
-
理解TCP是可靠的
TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。以下是TCP为何被认为是可靠的原因:
特性/机制 | 描述 |
---|---|
面向连接 | 在数据传输之前,TCP会建立一个连接,确保通信双方都准备好进行数据交换。 |
三次握手 | 建立连接的过程使用三次握手,确保双方的序列号同步,避免旧的连接请求被错误地接受。 |
数据分段 | TCP将应用层的数据分割成合适大小的段,便于网络传输。 |
序列号和确认应答 | 每个TCP段都有一个序列号,接收方会发送确认应答(ACK),以确保数据的有序接收。 |
数据重传 | 如果发送方没有在预定时间内收到确认应答,它会重新发送数据。 |
流量控制 | TCP使用滑动窗口机制来控制发送方的发送速率,以避免接收方处理不过来。 |
拥塞控制 | TCP通过慢启动、拥塞避免、快速重传和快速恢复等算法来避免网络拥塞。 |
错误检测 | TCP头部包含校验和字段,用于检测数据在传输过程中是否发生错误。 |
数据排序 | TCP确保接收到的数据段按照正确的顺序被重新组装。 |
连接终止 | TCP使用四次挥手过程来优雅地终止连接,确保所有数据都被正确传输。 |
以下是TCP可靠性的一些关键点:
数据完整性:通过校验和,TCP可以检测数据在传输过程中是否损坏,并在必要时重新传输。
数据有序性:序列号确保了数据按照发送顺序到达接收方。
数据传输可靠性:通过确认应答和重传机制,TCP确保所有发送的数据都被接收方正确接收。
流量控制:滑动窗口机制防止发送方发送数据过快,导致接收方来不及处理。
拥塞控制:TCP的拥塞控制算法帮助网络避免过载,从而保持数据传输的可靠性。 由于这些特性,TCP适用于需要高可靠性的应用,如Web浏览器、电子邮件、文件传输等。然而,这种可靠性也意味着TCP在某些情况下可能不如UDP(用户数据报协议)那样高效,因为UDP不提供这些可靠性保证,但它允许更快的数据传输速度。
-
为什么说UDP是不可靠的?
UDP(用户数据报协议)被认为是一种不可靠的传输层协议,原因在于它缺乏TCP(传输控制协议)中提供的一系列确保数据可靠传输的特性。下面是UDP不可靠性的几个关键点:
特性/机制 | 描述 | 不可靠性的影响 |
---|---|---|
无连接 | UDP不建立持续的网络连接。 | 发送和接收双方没有持续的状态信息,每次传输都是独立的。 |
无确认应答 | UDP不使用ACK机制来确认数据包的接收。 | 发送方无法知道数据包是否已经到达接收方,如果数据包丢失,不会有任何通知。 |
无重传机制 | UDP不会重传丢失的数据包。 | 如果数据包在传输过程中丢失,它将不会被重新发送,导致数据丢失。 |
无数据排序 | UDP不保证数据包的到达顺序。 | 数据包可能会以不同于发送顺序的方式到达,接收方可能接收到乱序的数据。 |
无流量控制 | UDP没有流量控制机制。 | 发送方可以以任何速度发送数据,不管接收方是否能够处理,可能导致接收方缓冲区溢出,数据丢失。 |
无拥塞控制 | UDP不实施拥塞控制。 | UDP不会根据网络拥塞情况调整数据传输速率,可能导致网络拥塞,增加数据丢失的可能性。 |
校验和可选 | UDP头部的校验和字段是可选的。 | 即使使用了校验和,它也只能检测错误,不会修复错误的数据包。如果没有使用校验和,甚至无法检测到错误。 |
、、、、、 | ||
以下是UDP不可靠性的一些具体表现:
-
数据丢失:由于没有重传机制,如果数据包在网络中丢失,它将不会被重新发送。
-
数据重复:由于没有确认应答和数据排序,可能会出现数据包重复到达接收方的情况。
-
数据损坏:即使使用了校验和,UDP也只能检测到错误,而不会修复错误的数据包。
-
网络拥塞:UDP不会根据网络拥塞情况调整传输速率,可能会导致网络拥塞,进一步影响数据传输的可靠性。
尽管UDP被认为不可靠,但它仍然在许多应用场景中非常有用,尤其是那些对实时性要求高,可以容忍一定数据丢失的应用,例如:
-
实时视频和音频流:如视频会议和流媒体服务,它们更关注流畅性而不是数据的完整性。
-
在线游戏:游戏通常需要低延迟的通信,即使偶尔的数据丢失也比延迟更好。
-
DNS查询:域名系统查询通常使用UDP,因为它需要快速响应,而且单个查询的数据量较小。
UDP的简单性和低开销使其在某些情况下比TCP更有效。
2.确认应答(ACK机制)
再谈ACK机制前,我们先举一个生活例子,生活中两个人说话,我怎么确定对方有没有收到我的话呢?我们是通过对方的应答,来确定对面有没有收到我说的话,只有对方应答了,我们才知道他听见了
而在客户端与服务端的通信过程中(TCP下),也是通过确定对方应答,来表明另一端收到了我的信息;只要收到了应答,就能保证我发的数据,对方一定收到了
所以双方进行通信时可能除了正常的数据段,还会包含确认数据段。
客户端向服务端发送数据,服务端收到后返回一条应答给客户端,表示服务端收到了;客户端可以一次只发送一条,但是在大部分场景下,客户端是一次发送多条数据段的,服务端也可以一次性返回多条应答
但是这些数据段到达对面的顺序不一定就是发送的顺序,比如发送4个数据段,结果只收到2个或者3个确认应答,客户端是如何知道哪个数据段发送失败了呢?
因为任何一方发送的一定含有报文,报文中就有一个属性叫做序号,TCP将每个字节的数据都进行了编号,即为序列号;
每一个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发
比如这里的客户端发送的数据段是1,报文中含有1000个字节的数据,如果服务端收到了,那么服务端返回给客户端的响应报头中的确认序号就填成1001,这个1001有两层含义:
-
告诉客户端,1001序列号以前的字节数据我已经收到了
-
告诉客户端,下次向我发送数据时应该从序列号1001开始
也正是因为有了连续应答,TCP允许对应答的少量缺失(比如我只返回4001,表示4001之前的我全部收到了)
如果1001报文丢失了,但其他的数据段传递到了服务端,服务端只会返回1001应答,表明1001以前的序列号都收到了
-
如何理解序列号?
所谓序列号就是该字节缓冲区数组的下标,数据从应用层拷贝到传输层发送缓冲区时,每个字节天然的有了一个编号;发送方发送的序号就是首个字节数据在发送缓冲区对应的下标,接收缓冲区响应应答的确认序号就是接收缓冲区接收到最后一个有效数据的下一个位置对应的下标
3.超时重传机制
丢包的两种情况
【情况一】发送的数据报文丢失了,此时发送端在一定时间内收不到对应的应答报文,就会进行超时重传
-
主机 A 发送数据给 B 之后,可能因为网络拥堵等原因,数据无法到达主机 B。
-
如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答,就会进行重发。
【情况二】应答报文丢失,此时发送端也会因为收不到对应的响应报文,而进行超时重传。但是主机 A 未收到 B 发来的确认应答,也可能是因为 ACK 丢失了。
因此主机 B 会收到很多重复数据,那么 TCP 协议需要能够识别出那些包是重复的包,并且把重复的丢弃掉。
这时候就可以利用前面提到的序列号,就可以很容易做到去重(通过序号)的效果。
那么,超时的时间如何确定呢?
• 最理想的情况下,找到一个最小的时间,保证“确认应答一定能在这个时间内返回”.
• 但是这个时间的长短,随着网络环境的不同,是有差异的.
• 如果超时时间设的太长,会影响整体的重传效率;
• 如果超时时间设的太短,有可能会频繁发送重复的包;
TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间
• Linux 中(BSD Unix 和 Windows 也是如此),超时以500ms 为一个单位进行控制,每次判定超时重发的超时时间都是 500ms 的整数倍.
• 如果重发一次之后,仍然得不到应答,等待2*500ms 后再进行重传.
• 如果仍然得不到应答,等待4*500ms 进行重传.依次类推,以指数形式递增.
• 累计到一定的重传次数,TCP 认为网络或者对端主机出现异常,强制关闭连接.
4.连接管理机制
在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接
服务端状态转化:
[CLOSED -> LISTEN]:服务器端调用 listen 后进入 LISTEN 状态,等待客户端连接。
[LISTEN -> SYN_RCVD]:一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列中,并向客户端发送 SYN 确认报文。
[SYN_RCVD -> ESTABLISHED]:服务端一旦收到客户端的确认报文,就进入 ESTABLISHED 状态,可以进行读写数据了。
[ESTABLISHED -> CLOSE_WAIT]:当客户端主动关闭连接(调用close), 服务器会收到结束报文段, 服务器返回确认报文段并进入CLOSE_WAIT;
[CLOSE_WAIT -> LAST_ACK]:进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据)。当服务器真正调用 close 关闭连接时, 会向客户端发送 FIN,此时服务器进入 LAST_ACK 状态,等待最后一个 ACK 到来(这个 ACK 是客户端确认收到了 FIN)。
[LAST_ACK -> CLOSED]:服务器收到了对 FIN 的 ACK,彻底关闭连接。
客户端状态转化: [CLOSED -> SYN_SENT]:客户端调用 connect,发送同步报文段。
[SYN_SENT -> ESTABLISHED]:connect 调用成功, 则进入 ESTABLISHED 状态,开始读写数据。
[ESTABLISHED -> FIN_WAIT_1]:客户端主动调用 close 时,向服务器发送结束报文段,同时进入 FIN_WAIT_1。
[FIN_WAIT_1 -> FIN_WAIT_2]:客户端收到服务器对结束报文段的确认,则进入 FIN_WAIT_2,开始等待服务器的结束报文段。
[FIN_WAIT_2 -> TIME_WAIT]:客户端收到服务器发来的结束报文段,进入 TIME_WAIT,并发出 LAST_ACK。
[TIME_WAIT -> CLOSED]:客户端要等待一个 2MSL(Max Segment Life,报文最大生存时间)的时间,才会进入 CLOSED 状态。
下图是 TCP 状态转换的一个汇总:
-
较粗的虚线表示服务端的状态变化情况。
-
较粗的实线表示客户端的状态变化情况。
-
CLOSED 是一个假想的起始点,不是真实状态。
三次握手
TCP三次握手是建立连接的过程,主要目的是为了确保通信双方都有能力发送和接收数据,从而建立一个可靠的通信通道。三次握手的具体过程如下:
-
第一次握手:客户端向服务器发送一个SYN(synchronize)请求报文,表示客户端请求建立连接。这时,客户端进入“SYN_SENT”状态,等待服务器的响应。
-
第二次握手:服务器收到客户端的SYN请求后,确认接收到请求,向客户端发送一个带有SYN和ACK(acknowledge)标志的报文。这表示服务器同意建立连接,并请求对客户端进行确认。服务器进入“SYN_RCVD”状态。
-
第三次握手:客户端接收到服务器的SYN+ACK报文后,向服务器发送一个ACK报文,确认已接收到服务器的回复。此时客户端和服务器都进入“ESTABLISHED”状态,连接正式建立,接下来可以进行数据传输。
-
-
建立连接并不是百分百成功的,如果第三次应答失败了呢?
客户端把ACK发送出去以后,客户端就认为三次握手已经完成了,因为建立连接的本质就是在赌,赌最后一个ACK一定收到了。建立连接的本质不就是进行数据的传输吗?客户端认为三次握手做好了,于是就开始给服务端发数据,服务端收到数据以后,就想我还没有三次握手完毕呢,你怎么就给我发数据了,服务端就知道,一定是最后一次应答丢失了,于是服务端返回一个报文,将RST置为1,告诉客户端,三次握手失败了,你需要重新与我建立连接,也就是连接重置;
RST:reset连接重置标志位,收到该标志位的主机,要对异常连接重新释放,重新建立
在日常中也有可能遇见连接重置的情况
-
为什么选择三次握手而不是一次二次握手?
1.验证全双工---验证网络的连通性
2.建立双方通信的共识意愿
选择三次握手而非一次或二次握手的主要原因在于确保连接的可靠性和数据传输的准确性,避免资源浪费和网络拥塞。三次握手机制在网络通信中具有以下几个关键作用:
防止已失效的连接请求报文再次传送 若采用一次或二次握手,当客户端发送连接请求并在网络中遭遇延迟或丢失情况时,旧的请求报文可能在网络中滞留并被服务器错误接收,导致服务器进入连接状态而客户端并未实际参与,从而引发资源浪费。三次握手可以有效确认双方的状态是否都处于准备连接状态,以防止旧的报文误导连接建立。
双方确认通信能力和确认信息可靠性 三次握手过程中的双方响应和确认步骤能够确保双方都具备发送和接收能力,避免了仅靠一次或二次握手确认双方状态不对称的问题。例如,在三次握手中,客户端会先发送请求并等待服务器响应;服务器响应后,客户端再进行确认。这个过程确保了服务器和客户端都明确对方的在线状态,并建立了可靠的连接。
避免资源过早分配 通过三次握手,服务器能够等到确认客户端的确认消息后,才正式分配资源来建立连接,避免一次或二次握手中由于客户端故障或其他原因而造成的连接失败,这样服务器可以在未确认连接稳定之前不投入过多资源,提高资源利用率和系统效率。
三次握手是用最小的成本验证全双工通信信道是通畅的
-
四次握手可不可以?
可以,但没有必要,会降低效率;服务端就是把第二次握手的SYN和ACK合并发送,这种做法不仅节省了一个确认报文包,还提高了连接建立的效率;这种合并发送的应答叫做捎带应答
几个注意点:
-
connect 函数不参与底层的三次握手,connect 函数的作用只是发起三次握手。
-
accept返回分配新的描述符和客户端通信也不参与三次握手的过程
四次挥手
四次挥手(Four-Way Handshake)是TCP协议中用于断开连接的过程,与三次握手相对应。四次挥手的设计是为了确保双方在断开连接前,都能确认彼此的关闭请求,以确保数据完整、避免信息丢失。
四次挥手的过程如下:
1.客户端发送关闭请求(FIN) 当客户端(发起方)希望断开连接时,会发送一个带有FIN标志位的报文给服务器,表示其完成了数据发送并希望关闭连接。此时,客户端进入“FIN-WAIT-1
”状态,等待服务器的响应。
2.服务器确认客户端的关闭请求(ACK) 服务器收到客户端的FIN请求后,发送一个带ACK标志位的确认报文,表示同意关闭客户端的连接。此时,服务器的连接还没有完全关闭,它可能仍有数据要发送。客户端在收到ACK后进入“FIN-WAIT-2
”状态,等待服务器的关闭请求。
3.服务器发送自己的关闭请求(FIN) 服务器在确认数据发送完成后,向客户端发送带有FIN标志的报文,表示它的数据已发送完毕且准备关闭连接。服务器进入“LAST-ACK
”状态,等待客户端的最终确认。
4.客户端确认服务器的关闭请求(ACK) 客户端收到服务器的FIN报文后,发送ACK确认报文,确认双方已准备断开连接。此时客户端进入“TIME-WAIT
”状态,等待一段时间(通常是2MSL,即最大报文生存时间),确保服务器能收到ACK报文。若该时间内未收到服务器的重发请求,客户端则彻底关闭连接。服务器在收到客户端的最终ACK后,也关闭连接,断开过程完成。
-
设计四次挥手的原因
四次挥手的设计确保双方都能在断开前完成数据传输,避免中途信息丢失。由于TCP是全双工通信(即双方的发送和接收通道独立),所以需要每个方向都独立关闭:客户端和服务器各发送各自的FIN请求,并在确认对方的ACK后,才正式关闭通道。
-
为什么四次挥手里面不使用捎带应答?
四次挥手中不使用捎带应答的原因主要是为了保证双方的连接关闭流程的独立性和数据传输的完整性。具体分析如下:
1.全双工连接的独立性 TCP连接是全双工的,即客户端和服务器各自的发送和接收通道是独立的。断开时,双方必须分别发送各自的关闭请求(FIN)和确认应答(ACK)。这样,即使一方希望关闭连接,另一方仍然可以继续发送数据,直到它的发送任务完成。四次挥手的设计保证了双向独立的确认过程:客户端和服务器分别确认各自的数据传输已完成,确保双方的连接关闭都是明确的,而捎带应答会破坏这种独立性。
2.确保数据传输完整性 在关闭连接前,双方都需要确保已完成的所有数据传输。捎带应答在三次握手中可以节省连接建立的确认步骤,但在连接关闭时则可能导致未传输的数据丢失。例如,如果服务器在确认客户端的FIN请求后立即发送自己的FIN而不单独发送ACK,则可能忽略客户端仍在接收的数据包。通过分步确认(四次挥手),每一方都能清楚地知道对方是否还在发送数据。
3.时间控制和可靠性保障 四次挥手中的TIME-WAIT状态用于确保服务器能收到客户端的最后ACK。如果使用捎带应答,连接关闭的顺序和时间控制会变得复杂,容易导致ACK丢失或重复FIN发送。此外,TIME-WAIT提供了一个缓冲时间,以便应对网络中的延迟情况,确保双方的关闭请求和确认响应均完整到达。
综上,四次挥手的设计确保了连接关闭时的双向独立性和数据完整性,不使用捎带应答是为了保证双方能够完全确认各自的数据发送与接收状态,避免连接关闭过程中的数据丢失或异常。
-
TIME-WAIT 状态的意义
客户端的“TIME-WAIT”状态是一种安全措施,用于等待一定时间确保最后的ACK报文确实到达服务器。如果服务器未收到ACK,它会重发FIN,客户端在TIME-WAIT状态下可再发ACK,确保连接关闭的可靠性。
理解TIME_WAIT状态
现在做一个测试,首先启动server,然后启动client,然后使用ctrl+C使server终止,这时马上再运行server,结果是
这是因为,虽然server的应用程序终止了,但TCP协议层的连接并没有完全断开,因此不能再次监听同样的server端口,我们用netstat命令查看一下
-
TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态
-
我们使用Ctrl + C 终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口
-
MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在Ubuntu与centos7上默认配置是60s
-
可以通过
cat /proc/sys/net/ipv4/tcp_fin_timeout
查看msl的值
为什么TIME_WAIT的时间是2MSL?
使用setsockopt()就可以解决这个问题,选择optname为1,表示允许创建端口号相同但IP地址不同的多个socket描述符
setsockopt
是一个在 POSIX 兼容的操作系统中使用的系统调用,它用于设置套接字(socket)的选项。套接字是支持 TCP/IP 网络通信的端点,而 setsockopt
允许程序在套接字级别上配置各种选项,从而影响套接字的行为。
-
MSL是TCP报文的最大生存时间,因此TIME_WAIT持续在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启,可能会收到来自上一个进程的迟到的数据,但是这种数据很可能是错误的)
-
同时也是在理论上保证最后一个报文可靠到达(假设最后一个 ACK 丢失,那么服务器会再重发一个FIN.这时虽然客户端的进程不在了,但是TCP 连接还在,仍然可以重发LAST_ACK);
-
解决TIME_WAIT状态引起的bind失败的方法
-
在server的TCP连接没有完全断开之前不允许重新监听,某些情况下可能是不合理的。
-
服务器需要处理非常大量的客户端的连接(每个连接的生存时间可能很短,但是每秒都有很大数量的客户端来请求)。
-
这个时候如果由服务端主动关闭连接(比如某些客户端不活跃,就需要被服务端主动清理掉),就会产生大量TIME_WAIT连接。
-
由于我们的请求数量很大,就可能导致TIME_WAIT的连接数很多,每个连接都会占用一个通信五元组(源ip,源端口,目的ip,目的端口,协议)。其中服务器的ip和端口和协议是固定的。如果新来的客户端连接的ip和端口号和TIME_WAIT占用的链接重复了,就会出现问题
修改我们之前的代码,这样就不会再出现绑定失败的错误了
理解CLOSE_WAIT状态
◉ 状态出现时机:CLOSE_WAIT
状态出现在服务器端接收到客户端的FIN包并回应了ACK包之后,但在服务器发送自己的FIN包之前。
◉ 状态含义:CLOSE_WAIT
状态表示服务器已经知道客户端想要关闭连接,但是服务器端还有未处理完的数据或者还需要做一些清理工作。在这个状态下,服务器端有一个任务:完成必要的清理工作,然后发送FIN包以关闭连接。
◉ 潜在问题:如果服务器端在CLOSE_WAIT
状态停留时间过长,可能会导致资源泄露,因为虽然客户端已经关闭了连接,但服务器端仍然保持着这个连接的某些资源。如果大量的连接都处于CLOSE_WAIT
状态,可能会导致服务器资源耗尽。
◉ 解决方法:通常,如果服务器端检测到CLOSE_WAIT
状态过多,应该检查代码中是否正确处理了连接关闭的逻辑。确保在接收到客户端的FIN包后,及时完成必要的清理工作,并正确发送FIN包以关闭连接。
我们测验一下,我们关闭服务器中的close
如果我们服务器卡顿,查一下是不是存在大量的close_wait状态,如果存在,这种情况就叫做文件描述符泄漏
当使用 netstat -apn | grep 8888
命令时,可能会看到连接处于 LAST_ACK
状态,这通常发生在以下情况
被动关闭方: 当服务器(或被动关闭方)已经发送了 FIN
并收到了客户端(或主动关闭方)的 ACK
时,它会进入 LAST_ACK
状态。此时,服务器正在等待来自客户端的最后一个 ACK
确认,以完全关闭连接。
小结:对于服务器上出现大量的CLOSE_WAIT状态,原因就是服务器没有正确的关闭socket,导致四次挥手没有正确完成.这是一个 BUG. 只需要加上对应的 close 即可解决问题.
相关文章:
【Linux-传输层协议TCP】TCP协议段格式+确认应答+超时重传+连接管理机制(三次握手、四次挥手、理解TIME_WAIT + CLOSE_WAIT)
TCP协议 TCP全称为“传输控制协议(Transmission Control Protocol)”人如其名,要对数据的传输进行一个详细的控制。 1.TCP协议段格式 下面是TCP报头各个字段的表格形式: 字段名称字段大小描述源端口16位发送端TCP端口号。目的端…...
怎样使用Modbus转Profinet网关连接USB转485模拟从站配置案例
怎样使用Modbus转Profinet网关连接USB转485模拟从站配置案例 Modbus转profinet网关可以将Modbus协议转化为profinet协议,以实现设备之间的数据交互。在实际使用过程中,我们需要使用Modbus协议进行设备通讯,而profinet协议则是用于工业自动化…...
从“自习室令牌”到线程同步:探秘锁与条件变量
目录 互斥 为什么需要锁 锁的原理--互斥 锁的使用 同步 锁的问题 条件变量 互斥 为什么需要锁 先看结果: 以下代码是我模拟创建线程抢票,由于不加锁导致票抢到了负数 main.cc: #include<vector> #include<iostream> #include"…...
Java 大视界 -- Java 大数据在智能政务舆情引导与公共危机管理中的应用(138)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
LeetCode[59]螺旋矩阵Ⅱ
思路: 这种题我第一次确实没做出来,第一次做的时候一圈一圈处理,发现圈数越往里,越乱,原来之前是没从圈数开始遍历。思路:第一个大循环先遍历圈数,一共遍历n/2圈,如果是奇数那就最后…...
【Python 算法 1.线性枚举】
我装作漠视一切,以为这样就可以不在乎 —— 25.3.17 一、线性枚举的基本概念 1.时间复杂度 线性枚举的时间复杂度为 O(nm),其中 n是线性表的长度。m 是每次操作的量级,对于求最大值和求和来说,因为操作比较简单,所以 …...
C# 嵌套类 详解
一个类在它的包容类外没有多大意义,就适合设计成嵌套类。 嵌套类:定义在另一个类内部的类。 包容类(外部类):包含嵌套类的类。 嵌套类的独特之处是可以为类自身指定private访问修饰符。 嵌套类能访问包容类的任何成…...
深度学习中学习率调整策略
学习率衰减策略是深度学习优化过程中的一个关键因素,它决定了训练过程中学习率的调整方式,从而影响模型收敛的速度和效果。不同的衰减策略在不同的任务和模型上可能有不同的表现,下面从我用到过的几个衰减策略进行记录,后续慢慢跟…...
基于Flask的东方财富网股票数据可视化分析系统
【大数据】基于Flask的东方财富网股票数据可视化分析系统 (完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统能够高效地从东方财富网抓取股票数据,并通过Python的强大数据处理能…...
卓越的用户体验需要智能内容
摘要:这篇文章指出静态文档已无法满足现代用户的需求,而智能内容则是构建卓越用户体验的关键。文章从智能内容的定义、优势和实际应用等方面进行了详细阐述,并强调了企业应积极拥抱智能内容,以提升客户满意度、降低成本并创造新的…...
c++基础知识-图论进阶
一、拓扑排序 1、基础知识 1)什么是拓扑排序 对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若,则u在线性序列中出现在v之前。 2)拓扑排序的操作方法 重复执行…...
Java 买百鸡问题
二阶买百鸡问题:母鸡5元一只,公鸡3元一只,35元可以有多少种买法刚好用完? package com.software.first;import java.util.Scanner;public class Test {public static void main(String[] args) {Scanner scan new Scanner(Syste…...
为什么手机上用 mA 和 mAh 来表示功耗和能耗?
在手机上,我们经常会看到 mA(毫安) 和 mAh(毫安时) 这两个单位,它们分别用来表示 功耗水平 和 能耗水平。为什么用这两个单位呢?其实这和电流、时间以及电池的特性有关。 1.mA(毫安…...
使用SDKMAN!安装springboot
在 Ubuntu 环境中使用 sdk install springboot 命令之前,您需要先安装 SDKMAN!(Software Development Kit Manager)。以下是详细的安装步骤: 安装 SDKMAN! 打开终端。 运行以下命令以安装 SDKMAN!: curl -s "htt…...
【AI学习从零至壹】Pytorch神经⽹络
Pytorch神经⽹络 神经网络简介神经元激活函数 神经网络神经⽹络的⼯作过程前向传播(forward) 反向传播(backward)训练神经⽹络 Pytorch搭建并训练神经⽹络神经⽹络构建和训练过程数据预处理构建模型优化器&提取训练数据训练样本 神经网络简介 神经元 在深度学习中&#x…...
Linux应用 / 驱动程序崩溃调试
文章目录 前言一、GDB 使用1. GDB 介绍2. Debug版本与Release版本3. 指令演示3.1 显示行号3.2 断点设置3.3 查看断点信息3.4 删除断点3.5 开启 / 禁用断点3.6 运行3.7 打印 / 追踪变量 4. 最常用指令 二、Linux 应用程序调试1. codedump 介绍2. 在 Linux 系统中使用 coredump2.…...
k8s集群-kubeadm init
为了使用阿里云的镜像源加速 kubeadm init 初始化 Kubernetes 集群的过程,你需要修改 kubeadm 的配置文件以指向阿里云提供的镜像仓库。以下是具体步骤: 1. 创建或编辑 kubeadm 配置文件 首先,创建一个 kubeadm 的配置文件(如果还…...
Python 视频爬取教程
文章目录 前言基本原理环境准备Python安装选择Python开发环境安装必要库 示例 1:爬取简单直链视频示例 2:爬取基于 HTML5 的视频(以某简单视频网站为例) 前言 以下是一个较为完整的 Python 视频爬取教程,包含基本原理…...
Linux应用软件编程(多任务:进程间通信)
一.进程间通信 同一主机下: (1)无名管道:pipe (2)有名管道:fifo (3)信号:异步通知机制 (4)共享内存&a…...
工厂方法模式和抽象工厂模式详解
由于工厂方法模式和抽象工厂模式有点类似,可以放着一块说下。 一、工厂方法模式 (Factory Method Pattern) 场景描述 假设需要实现一个跨平台日志系统,支持文件日志和数据库日志,且未来可能扩展其他日志方式。通过工厂方法模式,…...
js给后端发送请求的方式有哪些
在 JavaScript 中,有多种方式可以向后端发送请求,以下为你详细介绍: 1. XMLHttpRequest XMLHttpRequest 是最早用于在浏览器和服务器间进行异步通信的 API。虽然它使用起来相对复杂,但兼容性很好,能兼容较旧的浏览器…...
无人机吊舱模块更换技术难点分析!
一、模块更换的可行性 模块化设计的支持 部分吊舱采用模块化设计,允许根据任务需求更换传感器模块。例如,某些吊舱系统支持定制化组合,如“红外激光测距”或“可见光激光测距”等。这表明在硬件结构上,若吊舱预留了标准化的接…...
高数1.4 无穷小与无穷大
1.无穷小 1.1.定义 1.2 常规性质 2.无穷大 2.1 定义 2.无穷小与无穷大的关系...
深入理解MySQL数据库索引
深入理解MySQL数据库索引 个人主页:顾漂亮 1. 索引简介 1.1 索引是什么? MySQL的索引是一种数据结构,它可以帮助数据库高效地查询、更新数据表中的数据。索引通过一定的规则排列数据表中的记录,使得对表的查询可以通过对索引的搜…...
Spring 中 BeanPostProcessor 的作用和示例
一、BeanPostProcessor 的核心作用 1、作用 BeanPostProcessor 是 Spring Bean 实例级别的扩展接口,在 Bean 初始化前后对实例进行加工或替换。其核心功能包括: 修改 Bean 属性(如动态注入值、调整配置)。生成代理对象…...
图 最 短 路
Diikstra朴素 非负边权单源最短路顶点数最好小于1000少量数据结构知识和一点点的算法基础 算法描述 这个算法我们采用邻接矩阵来存储,有时候输入数据,并不是我们期待的那样,所以需要对数据做一些处理,也就是把图创建起来的过程…...
NA611系列WiFi串口服务器常见问题以及解决办法
NA611系列WiFi串口服务器是一款高性能、高可靠的工业级双频RS485 ⇌ WiFi数据双向透明传输的串口服务器。实现RS485串口数据通过WiFi实现设备联网数据交互,支持 IEEE 802.11 a/b/g/n 标准。WiFi串口服务器在连接、配置和使用过程中可能会遇到多种问题。以下是一些常…...
工程化与框架系列(36)--前端监控告警实践
前端监控告警实践 🔔 引言 前端监控是保障应用质量和用户体验的重要手段。本文将深入探讨前端监控的实现方案,包括性能监控、错误监控、用户行为监控等方面,以及相应的告警机制。 监控系统概述 前端监控系统主要包括以下方面:…...
【深度学习|目标检测】YOLO系列anchor-based原理详解
YOLO之anchor-based 一、关于anchors的设置二、网络如何利用anchor来训练关于register_buffer训练阶段的anchor使用推理阶段的anchor使用 三、训练时的正负样本匹配anchor匹配grid匹配 总结起来其实就是:基于anchor-based的yolo就是基于三个检测头的分支上的grids和…...
vue3+Ts+elementPlus二次封装Table分页表格,表格内展示图片、switch开关、支持
目录 一.项目文件结构 二.实现代码 1.子组件(表格组件) 2.父组件(使用表格) 一.项目文件结构 1.表格组件(子组件)位置 2.使用表格组件的页面文件(父组件)位置 3.演示图片位置 ele…...
【C/C++】文件句柄
什么是文件句柄? 文件句柄(File Handle)是操作系统中的一种抽象概念,它用来表示一个打开的文件或输入/输出设备。 文件句柄是程序与文件之间的桥梁,程序通过文件句柄来访问和操作文件的内容。 1. 文件句柄——作用 文…...
Matlab 基于专家pid控制的时滞系统
1、内容简介 Matlab 185-基于专家pid控制的时滞系统 可以交流、咨询、答疑 2、内容说明 略 在处理时滞系统(Time Delay Systems)时,使用传统的PID控制可能会面临挑战,因为时滞会导致系统的不稳定或性能下降。专家PID控制通过结…...
【高项】信息系统项目管理师(六)项目进度管理【3分】
项目进度管理是为了保证项目按时完成。对项目所需的各个过程进行管理,包括规划进度、定义活动、排列活动顺序、估算活动持续时间、制订项目进度计划和控制进度。小型项目中,定义活动、排列活动顺序、估算活动持续时间以及制订进度模型形成进度计划等过程的联系非常紧密,可以…...
通过MATLAB和Carsim进行联合仿真,利用强化学习实现自动驾驶人机控制权策略的详细步骤和示例代码
以下是一个通过MATLAB和Carsim进行联合仿真,利用强化学习实现自动驾驶人机控制权策略的详细步骤和示例代码: 步骤概述 Carsim配置:对Carsim进行必要的设置,包括车辆模型、道路场景等,并生成S - function接口。MATLAB环境搭建:在MATLAB中配置Carsim的S - function,并创建…...
iOS 模块化架构设计:主流方案与实现详解
随着 iOS 工程规模的扩大,模块化设计成为提升代码可维护性、团队协作效率和开发灵活性的关键。本文将探讨为什么需要模块化,介绍四种主流的模块化架构方案(协议抽象、依赖注入、路由机制和事件总线),并通过代码示例和对…...
PostreSQL指南-内幕探索-学习笔记-01-数据库集簇的逻辑与物理结构
目录 一、环境信息 二、参考内容 三、逻辑结构概念 四、物理结构概念 五、逻辑映射关系 1、数据库与oid映射关系 2、堆表对象与oid映射关系 五、物理映射关系 1、数据库与oid映射关系 2、堆表对象与oid映射关系 六、数据库文件布局 1、表格 2、postmaster.pid文件解…...
java使用(Preference、Properties、XML、JSON)实现处理(读写)配置信息或者用户首选项的方式的代码示例和表格对比
在Java应用程序中,处理应用首选项(preferences)有多种方法,包括使用java.util.prefs.Preferences类、属性文件(如.properties文件)、XML文件和JSON文件。下面是每种方法的详细说明和代码示例,最…...
spring动态代理是在生命周期的哪个阶段实现的
Spring AOP(面向切面编程)的动态代理是在 Bean 生命周期的 初始化后阶段 实现的,具体来说是在 BeanPostProcessor 的 postProcessAfterInitialization() 方法中完成的。下面我们来详细分析 Spring AOP 动态代理的实现位置及其工作原理。 1. S…...
Oracle静默安装方法
Web服务器上面的Linux一般是不会有图形界面的,所有通过图形界面来安装Linux的方式在没有图形界面的Linux上面是行不通的,我们要使用的安装方式叫做Linux的静默安装。即在没有图形界面的Linux上面安装。 1. 下载地址 http://www.oracle.com/technetwork…...
本地部署deepseek-r1建立向量知识库和知识库检索实践【代码】
目录 一、本地部署DS 二、建立本地知识库 1.安装python和必要的库 2.设置主目录工作区 3.编写文档解析脚本 4.构建向量数据库 三、基于DS,使用本地知识库检索 本地部署DS,其实非常简单,我写了一篇操作记录,我终于本地部署了DeepSeek-R1(图文全过程)-CSDN博客 安装…...
单词翻转(信息学奥赛一本通-1144)
【题目描述】 输入一个句子(一行),将句子中的每一个单词翻转后输出。 【输入】 只有一行,为一个字符串,不超过500个字符。单词之间以空格隔开。 【输出】 翻转每一个单词后的字符串,单词之间的空格需与原文一致。 【输入样例】 he…...
Python基础入门掌握(十三)
从基础到进阶,轻松掌握文件读写 目录 文件操作的基本概念 文件的打开与关闭 读取文件内容 写入文件内容 文件操作的高级技巧 总结与建议 文件操作的基本概念 在Python中,文件操作主要涉及以下几个步骤: 打开文件(open…...
【再读】R1-Onevision通过跨模态形式化为复杂多模态推理任务提供了系统性解决方案
R1-Onevision:跨模态形式化驱动的多模态推理技术突破,R1-Onevision通过跨模态形式化、双阶段训练和教育级基准测试,为多模态推理树立了新标杆。其技术创新不仅提升了模型在复杂任务中的表现,更重要的是为行业提供了一种可解释、可迁移的多模态处理范式。随着形式化方法的不断…...
【AWS入门】2025 AWS亚马逊云科技账户注册指南
【AWS入门】2025 AWS亚马逊云科技账户注册指南 A Guide To Register a New account on AWS By JacksonML 0. AWS亚马逊云科技简介 Amazon Web Service(AWS) 即亚马逊云科技,其在全球Cloud Computing(云计算)市场占有最为重要的地位。 AWS连续13年被Gartner评为…...
重生之我在学Vue--第18天 Vue 3 项目功能扩展
重生之我在学Vue–第18天 Vue 3 项目功能扩展 文章目录 重生之我在学Vue--第18天 Vue 3 项目功能扩展前言一、权限管理系统1.1 用户角色体系设计1.2 路由权限控制1.3 组件级权限控制 二、分页与搜索系统2.1 分页类型对比2.2 分页组件实现2.3 搜索功能实现 三、文件上传系统3.1 …...
基于SpringBoot的房地产销售管理系统【附源码】
基于SpringBoot的房地产销售管理系统(源码L文说明文档) 目录 4 系统设计 4.1用户登录功能的详细实现 4.2管理员权限的功能实现 4.2.1客户信息管理功能的详细实现 4.2.2房产管理功能的详细实现 4.2.3预约看房功能的详细实现 4.2.4论…...
数组题型-二分查找-JS
二分查找伪代码 1.定义 target 是在⼀个在左闭右闭的区间⾥,也就是[left, right] let left0;let rightnums.length-1;// 定义target在左闭右闭的区间⾥,[left, right]while(left<right){// 当leftright,区间[left, right]依然有效&#x…...
STL——vector
目录 1 vector介绍 2 vector使用 2.1 vector的定义 2.1.1 无参构造 2.1.2 构造并初始化N个Val 2.1.3 拷贝构造 2.1.4 使用迭代器初始化构造 2.1.5 使用大括号初始化构造 2.2 vector的迭代器 2.2.1 const 迭代器 2.3 vector的空间增长 2.4 vector的增删改查 2.5 ve…...
国内首款载重1吨级无人运输机TP1000首飞成功 2026年投入应急救援
大湾区经济网珠海快讯,据央视新闻报道,3月15日上午,国内首款载重1吨级大型无人运输机TP1000在山东成功首飞。该机由中国民航适航标准完全自主研发,起飞重量3.3吨,满载航程达1000公里,具备智能空投功能&…...
python-leetcode 54.全排列
题目: 给定不含重复数字的数组nums,返回其所有可能的全排列,可以按任意顺序返回答案 回溯法 一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通…...