TCP 三次握手(建立连接)
三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息。
第1次握手
客户端:
发送 SYN(SYN=1),seq=x 包
进入 SYN_SENT 状态
第2次握手
服务器:
发送 ack=x + 1, seq=y, SYN=1, ACK=1
进入 SYN_RECV 状态
第3次握手
客户端:
SYN=0, ACK=1, seq=x+1, ack=y+1
客户端此包发送完毕之后,客户端和服务器进入 ESTABLISHED(TCP 连接成功) 状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
TCP 四次挥手(断开连接)
第1次
客户端:
发送报文 FIN=1, seq=u(等于前面已经发送过来的数据的最后一个字节的序号加1)
进入 FIN-WAIT-1(终止等待1) (TCP 规定,FIN 报文段即使不携带数据,也要消耗一个序号)
第2次
服务器:
收到连接释放报文
发出确认报文,ACK=1, ack=u+1,并且带上自己的序列号 seq=v
进入 CLOSE-WAIT(关闭等待) 状态
TCP 通知应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接收。这个状态还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间。
客户端:
接收到服务器的确认请求
进入 FIN-WAIT-2(终止等待2) 状态,等待服务器发送连接释放报文(这之前还需要接受服务器发送的最后的数据)。
第3次
服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,由于在半关闭状态,服务器很可能又发送了一些数据。假定此时的序列号为 seq=w
服务器:
FIN=1, ACK=1, ack=u+1, seq=w(新的seq)
进入 LAST-ACK 状态
第4次
客户端:
客户端接收到服务器的连接释放报文之后,必须发出确认。
ACK=1, ack=w+1, seq=u + 1
客户端进入 TIME-WAIT(时间等待) 状态
经过 2 MSL(Maximum Segment Lifetime)(报文最大生成时间),进入 CLOSED 状态
服务器:
只要接收到了客户端发出的确认,立即进入 CLOSED 状态
服务器比客户端先进入 CLOSED 状态。
为什么3次握手
当 Server 收到 Client 端的 SYN 连接请求报文后,可以直接发送 SYN、ACK 报文。ACK 报文做应答, SYN 报文用来同步。
3 次握手做好发送数据的准备工作,同时也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
前两次握手进行同步和准备,第三次握手进入状态。
为什么不是2次握手呢?
如果一个连接请求在网络中跑得慢,超时了,这时客户端会重发请求,但这个跑的慢的客户端最后还是跑到了,然后服务端就接收了两个请求,然后全部回应就会创建两个连接,浪费资源。如果加入第三次验证,则客户端接收到一个服务端确认连接请求之后,后面再接收到确认连接请求就可以抛弃不管了。
为什么4次挥手
TCP 是双向的,所以需要在两个方向分别关闭,每个方向的关闭又需要请求和确认,所以一共就4次。
客户端:服务器大哥我要停止传输了(FIN-WAIT-1)
服务器:好的,我知道了(但可能我还有剩余的数据要据需传给你)(CLOSE-WAIT)
客户端:服务器大哥已经知道我要断开连接了(FIN-WAIT-2)
服务器:客户端小伙,我的数据传完了,我也不再给你发数据了(LAST-ACK)
客户端:好的,大哥不传数据了,那我进入 TIME-WAIT 了,再进行 2 MSL 我就进入 CLOSED 啦
服务器:那我断开连接了,bye bye(CLOSED)
如果已经建立了连接,但是客户端出现故障该怎么办
TCP 有一个保活计时器,客户端出现故障了,服务器是不能一直等下去浪费资源的的。
服务器每收到一次客户端请求后都会重新复位这个计时器,时间通常为 2h ,如果 2h 还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75s 就会发送一次。若一连发送10个探测报文仍然没有反应,服务器就认为客户端出现故障,接着就关闭连接。
SYN 洪水攻击
SYN 洪水攻击发送在3次握手的前2次,攻击者发送 TCP SYN,SYN 是 TCP 三次握手中的第一个数据包,当服务器返回 ACK 后,攻击者不对其进行再确认,那这个连接就处于挂起状态,也就是所谓的半连接状态,服务器收不到再确认的话,还会重复发送 ACK 给攻击者,这会导致服务器资源被浪费。攻击者对服务器发送非常大量的这种 TCP 连接,由于大量半连接状态在服务器产生,服务器的资源消耗会不断增加,最后导致服务器故障。
服务器发送 ACK 之后处于 SYN_RECV 状态,服务器只有收到客户端的 ACK 之后,才会转入 ESTABLISHED 状态。
缩略词相关
序列号 seq:占4个字节,用来标记数据段的顺序,TCP 把连接中发送的所有数据字段都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号之后,就给每一个报文段指派一个序号,序列号 seq 就是这个报文段中的第一个字节的数据编号。
当发送一个数据时,数据时被拆成多个数据包来发送,序列号就是对每个数据包进行编号,这样接收方才能对数据包进行再次拼接。
初始序列号是随机生成的,这样不一样的数据拆解保证就不会连接错误。确认号 ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号。序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期待接收到下一个字节的编号;即当前报文段最后一个字节的编号 +1 就是确认号。
确认 ACK:占1位, 代表确认接收,不管是三次握手还是四次分手,在回应的时候会加上 ACK = 1,表示消息接收到了,并且在建立连接之后发送数据时,都需加上 ACK = 1,来表示数据接收成功了。
仅当 ACK=1 时,确认好字段才有效。ACK=0 时,确认号无效。同步 SYN (Synchronize Sequence Numbers) 同步序列编号,代表请求创建连接,在三次握手中前两次要请求创建,表示这两次用于创建连接。
建立连接时用于同步序号。当 SYN=1,ACK=0 时表示,这是一个连接请求报文段。若同意连接,则在响应报文段中让 SYN=1,ACK=1。 SYN=1 表示这是一个连接请求,或连接接受报文。
SYN 这个标志位只有在 TCP 建立连接时才会被置1,握手完成后 SYN 标志位被置 0.终止 FIN: 表示请求关闭连接,在四次分手时,FIN 发了两遍。这是因为 TCP 的连接是双向的,所以一次 FIN 只能关闭一个方向。
FIN=1 表示,此报文的发送方的数据已经发送完毕,并要求释放连接。
SYN、ACK、FIN 这些大写的单词表示标志位,其值只有0、1;小写的 seq、ack 表示序号。
SYN、ACK、FIN 存放在 TCP 的标志位。
字段 | 含义 |
---|---|
ACK | 确认号是否有效,一般置为1 |
SYN | 请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设为1 |
FIN | 希望断开连接 |
URG | 紧急指针是否有效。为1表示某一位需要被优先处理 |
PSH | 提示接收端应用程序立即从 TCP 缓冲区把数据读走 |
RST | 对方要求重新建立连接,复位 |
一个想要分享点知识的公众号,关注送技术资料