TCP协议
传输控制协议,是一种面向连接、可靠的数据传输协议,它是为了在不可靠的互联网上提供可靠的端到端字节流而专门设计的一个传输协议。
-
面向连接:数据传输之前客户端和服务器端必须建立连接
-
可靠的:数据传输是有序的 要对数据进行校验
三次握手
为了保证客户端和服务器端的可靠连接,TCP建立连接时必须要进行三次会话,也叫TCP三次握手,进行三次握手的目的是为了确认双方的接收能力和发送能力是否正常。
三次握手过程简述
一次握手:客户端向服务端发送请求报文(SYN=1,seq=x),服务端可知客户端发送能力正常,自身接收能力正常
二次握手:服务端接受链接后回复报文(SYN=1、ACK=1、ack=seq+1、seq=y),并为这次连接分配资源。这时客户端可以知道服务器收发能力正常,自己收发能力正常;服务器知道自己收发能力正常,但不知道客户端接收能力正常,因此需要第三次握手。
三次握手:客户端接收到 ACK 报文后也向 Server 段发送报文(ACK=1、ack=y+1、seq=y+1),并分配资源,这样 TCP 连接就建立了。这时服务器可以确认客户端收发能力
SYN:同步位,SYN=1,表示进行一个连接请求
ACK:确认位, ACK=1,确认有效
ACK=0,确认无效
ack:确认号,对方发送seq+1
seq:序号
次数 | 发送路径 | 报文信息 | 目的 |
一次握手 | C->S | SYN=1、seq=x | C:自己发信息正常 S:自己收信息正常,C发消息正常 |
二次握手 | S->C | SYN=1、ACK=1、ack=x+1、seq=y | C:自己收信息正常,S收发信息正常 S: 自己发消息正常,但S不知道C收消息是否正常->需要第三次握手 |
三次握手 | C->S | ACK=1、ack=y+1、seq=y+1 | S:C接收信息正常 |
为什么需要第三次通信 ?
1、在第一次通信过程中,客户端向服务端发送信息之后,服务端收到信息后可以确认自己的收信能力和客户端的发信能力没有问题。
2、在第二次通信中,服务端向客户端送信息之后,客户端可以确认自己的发信能力和服务端的收信能力没有问题,但是服务端不知道自己的发信能力到底如何,所以就需要第三次通信。
3、在第三次通信中,A向B发送信息之后,B就可以确认自己的发信能力没有问题。
4、 小结:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
四次挥手
四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
四次挥手过程简述
一次挥手:客户端向服务器发送FIN报文(FIN=1,seq=u),发完后进入FIN_WAIT_1
状态,即主动关闭TCP连接,不再发送数据,但可以接收服务器发来的报文,等待服务器回复
二次挥手:服务器接到FIN报文后,返回一个ACK报文(ACK=1,ack=u+1,seq=v),表明自己接收到此报文,服务器进入CLOSE_WAIT关闭等待状态,此时客户端就知道服务端接到自己的断开连接请求,进入到FIN_WAIT_2状态,TCP处于半关闭状态,但服务器端可能还有数据要传输。
三次挥手:服务器关闭客户端连接,发送FIN报文(FIN=1,seq=w,ack=u+1)给客户端,此时服务器处于LAST_ACK状态,等待客户端回应。
四次挥手:客户端收到FIN报文后,发送一个ACK(ACK=1,ack=w+1,seq=u+1)给服务器作为应答,此时客户端处于TIME_WAIT
状态,这个状态是为了等待足够的时间以确保TCP接收到连接中断请求的确认。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
①因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
②但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。
③只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
TCP十一种状态
1.CLOSED:初始状态,表示TCP连接是”关闭着的”或”未打开的”
2.LISTEN:表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接
3.SYN_RCVD:表示服务器接收到了来自客户端请求连接的SYN报文。这个状态是在服务端的,但是它是一个中间状态,很短暂,平常我们用netstat或ss的时候,不太容易看到这种状态,但是遇到SYN flood之类的SYN攻击时,会出现大量的这种状态,即收不到三次握手最后一个客户端发来的ACK,所以一直是这个状态,不会转换到ESTABLISHED
4.SYN_SENT:这个状态与SYN_RCVD状态相呼应,,它是TCP连接客户端的状态,当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随机进入到SYN_SENT状态,并等待服务端的SYN和ACK,该状态表示客户端的SYN已发送
5.ESTABLISHED:表示TCP连接已经成功建立,开始传输数据
6.FIN_WAIT_1:这个状态在实际工作中很少能看到,当客户端想要主动关闭连接时,它会向服务端发送FIN报文,此时TCP状态就进入到FIN_WAIT_1的状态,而当服务端回复ACK,确认关闭后,则客户端进入到FIN_WAIT_2的状态,也就是只有在没有收到服务端ACK的情况下,FIN_WAIT_1状态才能看到,然后长时间收不到ACK,通常会在默认超时时间60s(由内核参数tcp_fin_timeout控制)后,直接进入CLOSED状态
7.FIN_WAIT_2:这个状态相比较常见,也是需要注意的一个状态,FIN_WAIT_1在接收到服务端ACK之后就进入到FIN_WAIT_2的状态,然后等待服务端发送FIN,所以在收到对端FIN之前,TCP都会处于FIN_WAIT_2的状态,也就是,在主动断开的一端发现大量的FIN_WAIT_2状态时,需要注意,可能时网络不稳定或程序中忘记调用连接关闭,FIN_WAIT_2也有超时时间,也是由内核参数tcp_fin_timeout控制,当FIN_WAIT_2状态超时后,连接直接销毁
8.CLOSE_WAIT:表示正在等待关闭,该状态只在被动端出现,即当主动断开的一端调用close()后发送FIN报文给被动端,被动段必然会回应一个ACK(这是由TCP协议层决定的),这个时候,TCP连接状态就进入到CLOSE_WAIT
9.LAST_ACK:当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK的状态,当收到对方的ACK之后,就进入到CLOSED状态了
10.TIME_WAIT:该状态是最常见的状态,主动方在收到对方FIN后,就由FIN_WAIT_2状态进入到TIME_WAIT状态
11.CLOSING:这个状态是一个比较特殊的状态,也比较少见,正常情况下不会出现,但是当双方同时都作为主动的一方,调用 close() 关闭连接的时候,两边都进入FIN_WAIT_1 的状态,此时期望收到的是ACK包,进入 FIN_WAIT_2 的状态,但是却先收到了对方的FIN包,这个时候,就会进入到 CLOSING 的状态,然后给对方一个ACK,接收到 ACK 后直接进入到 CLOSED 状态。