TCP

TCP主要通过连接管理,序列号,确认应答,超时重传,流量控制,拥塞控制

连接管理:四次挥手和三次握手

序列号:能够保证可靠性,既能防止数据丢失,又能避免数据重复。

确认应答:接受方接收到数据后,能回传ACK报文

超时重传,当数据包丢失或者确认包丢失,进行超时重传

流量控制:接受包接受数据的能力有限,方发送数据速度过快,出现接受端缓存溢出的现象,TCP根据接收端处理数据能力,决定发送方的速度

拥塞控制:当网络拥堵严重时,发送方减少数据发送

TCP和UDP区别
特性 TCP UDP
连接方式 面向连接(三次握手) 无连接
传输模式 一对一 一对一、一对多、多对多
可靠性 可靠传输 尽最大努力交付
拥塞/流量控制 支持 不支持
首部开销 较大(20字节) 较小(8字节)
有序性/边界 有序传输、无消息边界 可能乱序,有消息边界

三次握手

tcp头部包括序列号,源端口号和目标端口号,确认应答号

客户端先发送SYN消息给服务器,服务器收到之后返回ACK-SYN确认包给客户端,之后客户端发送一个确认消息确认服务端已经收到了SYN-ACK消息,至此建立连接成功

第一次握手过程:服务端收到客户端的SYN请求后,内核把连接存储到半连接队列,向客户端响应SYN-SCK报文,接着客户端返回ACK报文,内核将连接从半连接队列中移除,将创建新的完全的连接,将其添加到accept队列,等待进程调用accept()将连接取出来

所以当大量的syn报文给服务端,TCP的半连接队列就会埋怨,后续接受到的SYN报文就会被丢弃,导致客户端和服务端无法建立连接

三次握手:避免历史错误连接的建立,减少通信双方的不必要的资源消耗,帮助通信双方同步初始化序列号,完成握手后,连接被保存到内核的全连接队列,抵用accept把连接取出来给用户程序使用

如果第三次确认包丢失,服务器迟迟接受不到,就会触发超时重传机制,重新发送SYN-ACK报文,如果超时重传三次SYN后,达到最后重传次数,断开连接

如果第二次握手,服务端的SYN-ACK报文丢失后,客户端会认为是自己的SYN报文丢失,触发超时重传机制,重传SYN报文,同时服务端会重传SYN-ACK报文

四次挥手

客户端向服务端发送FIN报文,进入FIN-WAIT-1状态

服务端收到FIN报文,回复ACK报文,进入CLOSE-WAIT状态,并且TCP协议栈在FIN包插入EOF到接受缓存区,服务端通过read调用感知FIN包,EOF放在一排队等候的其他已接受的数据之后,必须通过read接受缓冲区已接受的数据,接着服务端在read数据时读到EOF,这时服务端应用程序如果有数据要接受的话,接受完后关闭连接,服务端返回FIN报文,进入LAST-ACK状态

客户端接收到FIN报文后,发送确认ACK给服务端,客户端进入TIME_WAIT状态

服务端接受ACK确认包,进入最后的CLOSE状态

客户端经过2MSL事件后,进入CLOSE

总结就是:

流程图:

图片取自小林coding
​​​​​
中间两次挥手为什么不能变成一次?

因为客户端发送FIN报文给服务端 ,内核会马上响应ACK,但是此时并不确定服务端是否还有数据要发送,所以我们需要将发送FIN报文的权限交给服务端

第三次挥手一直没发?

当客户端接受到ACK报文后就,进入FIN_WAIT2状态,表示客户端发送通道已经关闭,接下来需要等待服务端发送FIN报文

当第三次挥手一直没发,客户端持续等待,卡在FIN_WAIT_2连接僵死,系统资源被占用,资源泄露连接耗尽

第二次和第三次挥手之间,主动断开的那端能干什么

客户端调用shutdown函数关闭连接,服务端还可以接受数据

断开连接时客户端 FIN 包丢失,服务端的状态是什么?

单给客户端调用close函数时,向服务端发送FIN报文,如果此时接受到服务端的ACK报文,进入FIN_WAIT_2状态,但是当第一次挥手丢失,客户端超时重传

为什么四次挥手之后需要等待2MSL?

MSL 是 Maximum Segment Lifetime,报文最大生存时间

四次挥手,客户端进行TIME_WAIT状态,等待2MSL是为了最后一个ACK能被服务端接收到,如果服务端并没有接收到客户端发送的ACK包,那么2MSL时间可以确认服务端没有接受到ACK包可以重发FIN包让客户端接收到

服务端出现大量的timewait:HTTP没有使用长连接

或者长连接超时HHTP长连接请求数量达到上限

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐