这里主要记录在日常中对知识的学习,通过结合笔记与自身理解的方式尝试写下总结
文章对细节可能不会一一介绍解释,内容仅作参考
前段时间看了HTTP相关的知识,但感觉还有还多细节面没有了解到位。这次补充与TCP连接有关的
一、头部字段
一些需要前置了解的知识点
- Sequence number 顺序号码:保证TCP传输的报文都是有序的
- Acknowledge number 确认号码:表示数据接收端期望接收的下一个字节的编号是多少,并表示上一个序号已接收完成
- 确认方Ack = 发起方Req+1,两端配对
- Window Size 窗口大小:表示还能接收多少字节的数据,用于流量控制
- RTT:表示发送端发送数据到接收到对端数据所需的往返时间
标识符:
- URG=1: 表示本数据报的数据部分包含紧急信息,是一个高优先级数据报文,此时紧急指针有效。紧急数据一定位于当前数据报数据部分的最前面,紧急指针标明了紧急数据的尾部
- ACK=1: 表示确认字段有效。TCP还规定在连接建立后传送的所有报文段都必须把ACK置为1
- PSH=1: 表示接收端应该立即将数据push给应用层,而不是等到缓冲区满后再提交
- RST=1: 表示当前TCP连接出现严重问题,可能需要重新建立TCP连接,也可能用于拒绝非法的报文段和拒绝连接请求
- SYN=1: 当SYN=1,ACK=0时,表示当前报文段是一个连接请求报文;当SYN=1,ACK=1时,表示当前报文段是一个同意建立连接的应答报文
- FIN=1: 表示此报文段是一个释放连接的请求报文
二、三次握手
在TCP协议中,主动发起请求的一端为客户端,被动连接的一端为服务端。不管是客户端还是服务端,TCP连接建立完成后都能发送和接收数据,所以TCP是一个全双工的协议
一次TCP的建立需要进行三次对话,从而确定一个连接,进而开始通讯
过程如图所示:
- 第一次握手:客户端向服务端发送链接请求报文段。该报文段中包含自身的数据通讯初始序号Seq=X和连接请求SYN。请求发送后,客户端进入SYN-SENT状态
- 第二次握手:服务端收到链接请求报文段后,如果同意连接,则会发送一个包含自身的数据通讯初始序号Seq=Y、确认序号Ack=X+1和应答标识ACK的确认应答。发送完成后,服务端进入SYN-RECEIVED状态
- 第三次握手:当客户端收到连接同意的应答后,还要向服务端发送一个确认报文(Ack=Y+1,Seq=Z,ACK)。客户端发完这个报文段后进入ESTABLISHED状态,此时连接建立成功
明明两次握手就可以建立连接,为什么还需要第三次应答呢:
因为这是为了防止失效的连接请求报文段被服务端接收,从而产生错误
如果是这样:客户端发送了一个连接请求A,但是因为网络原因造成了超时,这时TCP会启动超时重传的机制再发送一个连接请求B。此时请求B顺利到达服务端,服务端应答完成就建立连接。如果连接请求A在两端关闭后终于到达了服务端,那么这时服务端会认为客户端又需要建立TCP连接从而应答后进入ESTABLISHED状态。此时客户端其实是CLOSED状态,那么就会导致服务端一直等待,造成资源浪费
在建立连接中,任意一端掉线,TCP都会重发SYN包,一般会重试5次,在建立连接中可能会遇到SYN FLOOD攻击,可以选择调低重试次数或干脆在不能处理的情况下拒绝请求
三、四次挥手
TCP是全双工的,在断开连接时两端都需要发送FIN断开请求和ACK确认
过程如图所示:
- 第一次挥手:客户端认为数据发送完成,向服务端发送连接释放请求
- 第二次挥手:服务端收到连接释放请求,会告诉应用层要释放TCP连接。然后发送确认应答,并进入CLOSE_WAIT状态,表示客户端到服务端的连接已经释放,不接收客户端发的数据了。但是因为TCP连接是双向的,所以服务端仍旧可以发送数据给客户端
- 第三次挥手:如果此时服务端还有没有发完的数据,会继续发送。等到发送完毕后会向客户端发送连接释放请求,并进入LAST-ACK状态
- 第四次挥手:客户端收到释放请求后,会向服务端发送确认应答。此时客户端进入TIME-WAIT状态,会持续2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃),若该时间段内没有服务器的重发请求的话,就进入CLOSED状态。当服务端收到确认应答的时候,也进入了CLOSED状态
为什么客户端要进入TIME-WAIT状态,等待2MSL后才进入CLOSED状态呢:
为了保证服务端能收到客户端的确认应答。若客户端发完确认应答后直接进入CLOSED状态,如果确认应答因为网络问题一直没有到达,那么会造成服务端不能正常关闭
为什么连接的时候是三次握手,关闭的时候却是四次握手:
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,"你发的FIN报文我收到了"。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手