TCP三次握手和四次挥手

该来的,该看的,终归是要看。因为它是你知识拼图里不可少的环节。

主要参考

书籍:《计算机网络》

博客:网络里,太多,没什么实质内容,多数和书籍一样。

网络里有很多复杂的知识点,太多,不想纠缠这些,只关心两个东西,一个握手,一个挥手。

TCP的首部格式:

首部格式我直接已书籍为准:

源端口和目的端口:

各占2个字节。分别表示源端口号和目的端口号。

序号(报文段序号Sequence Num):

占4字节。由于TCP是面向字节流的,因此一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个需要传送的字节流的起始序号必须在连接建立时设置。所以首部中的序号字段的值是本报文段所发送的数据的第一个字节的序号。例如:一个报文段的序号是301,携带总共100个字节。那么本报文的序号就是301。而下一个报文段的起始序号则是401。

确认号(Acknowledgment Number):

占4字节。是期望收到对方下一个报文段的第一个数据字节的序号。例如:B正确收到A发送过来的一个报文段,序号是501,数据长度是200(501-700),这就表明B已经正确接收到了A发送的序号到700为止的数据。在此基础上,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文中把确认号设置为701。

数据偏移(Offset):

占4位。表明TCP报文段的首部长度。

保留:

占6位。目前设置为0。

URG(URGent):

设置为1时,表明紧急指针字段有效。需要优先处理。

确认ACK(ACKnowledgment):

设置为1时,确认号有效。类似于一个开关。设置为0时,确认号无效。TCP规定,在连接建立之后所以传送的报文段都必须把ACK置为1。

推送PSH(Push):

设置PSH为1时,接收方就会尽快交付接收应用进程,而不等待整个缓冲区填满后再向上交付,不常使用。

复位RST(ReSeT):

设置为1时,表名TCP连接中出现严重差错,必须释放连接。还用来拒绝一个非法报文段或拒绝打开一个连接。

同步SYN(SYNchronization):

建立连接时同步序号。当SYN=1而ACK=0时,表名这是一个连接请求报文段。如果接收方同意建立连接,则会在相应报文段中使SYN=1和ACK=1。

终止FIN(FINis):

释放一个连接。FIN=1时表明此报文段的发送方的数据已发送完毕,要求释放运输连接。

窗口:

占2个字节。指的是发送本报文段的一方的接收窗口。窗口的值会告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(字节为单位)。例如:发送一个报文段,确认号是701,窗口字段是1000,就是告诉对方接下来你发送时的字节号要在701-1000之间。次值动态变化。

校验和:

占2字节。检验的范围包括首部和数据两部分。

紧急指针:

占2字节。仅在URG=1才有意义。表明本报文段中的紧急数据的字节数。

选项:

长度可变,最长达40字节,未使用选项时,首部长度是20字节。

TCP的三次握手:

 

在最新的书中已经把三次握手这种说法更新了。其实是一次握手,但是存在三次报文的发送。

 

前提:

1. A主动打开连接,B被动打开连接。

2. 一开始,B的TCP服务器进程先创建TCB(传输控制块),准备接收客户进程的连接作准备。然后服务器进程处于LISTEN(收听)状态

过程:

A->B(1):当需要建立TCP连接时,A向B发出请求报文段,首部中的同步位SYN=1,同时会带着一个初始序号seq=x。(TCP规定SYN报文段(即SYN=1的报文段)不能携带数据,但是需要消耗掉一个序号)。此时TCP客户端进程进入SYN-SENT(同步已发送)状态。

 

B->A(2):B收到请求报文之后,如果同意建立连接,则会向A发送确认。确认报文段中SYN=1和ACK=1,确认号为ack=x+1。同时自己也需要一个序号为seq=y。此确认报文也不能携带数据,但是需要消耗一个序号。此时TCP服务器进程进入SYN-RCVD(同步收到)状态。

 

A->B(3):TCP客户进程收到B的确认后,需要再次发送确认。ACK=1,确认号ack=y+1,而自己的序号seq=x+1。(TCP标准规定,ACK报文段可以携带数据,如果不携带数据则不需要消耗序号,这种情况下,下一个报文段的序号仍然是seq=x+1)。此时TCP连接建立,客户端A进入ESTABLISHED(已建立连接)状态。而此时服务端B在收到A的确认后也进入ESTABLISHED状态。

 

问题?为什么A最后还需要再发送一次确认呢?

主要是为了防止已经失效的连接请求报文段突然又传到B,因而产生错误。

已经失效的连接请求是怎么产生的?

正常情况A发出连接请求1,但是因为连接请求报文丢失而未收到确认。于是A又发出连接请求2,对于请求2来说,B正常收到并且给出了确认请求,建立连接,数据传输,然后释放连接。

异常情况A发出连接请求1,但是因为某个网络节点造成滞留导致B未收到。于是A又发出连接请求2,对于请求2来说,B正常收到并且给出了确认请求,建立连接,数据传输,然后释放连接。但是此时实际上已经通信已经结束,但是请求1又一次到达B,但是B不能区分正常异常的情况,所以以为又是一个正常的请求,所以发出确认,建立连接,但是A没有发出请求连接。所以不会理睬B的确认,但是B确以为新的连接建立了,等待A发送数据。

采用三报文握手的方法,就是防止的上述异常情况的出现,B发送了确认给A,A由于不会向B发送确认,所以B不会为这一次请求建立连接。

 

TCP的四次挥手:

 

过程:

A->B:A向B发送连接释放报文,并停止发送数据。FIN=1.序号seq=u(u=已传送的数据的最后一个字节序号加1)。此时A进入FIN-WAIT-1(终止等待1)。等待B的确认。(TCP规定,FIN报文段即使不携带数据也需要消耗一个序号)。

B->A:B收到释放请求后随即发出确认,ACK=1,确认号是ack=u+1。此报文自带的序号是v(v=已传送过的数据的最后一个字节序号+1)。随后B进入CLOSE-WAIT(关闭等待)状态。同时TCP服务器进程会通知高层应用进程,因而A到B这个方向的连接就释放了,这时的TCP连接处于半关闭(half-close)状态。

这个阶段是A到B的方向关闭了,表明了A到B没有数据需要传输,但是B到A没有关闭,如果B发送数据,A仍然要能接收。

B->A:A收到确认后,进入FIN-WAIT2(终止等待2)状态。等待B发出释放的连接释放报文段。如果此时B没有数据需要发送了,其应用进程就通知TCP释放连接,B发出连接释放报文段使用FIN=1,ACK=1,seq=w(在半关闭状态时可能B传送了一些数据给A),ack=u+1。此时B进入LAST-ACK(最后确认)状态。

A->B:A收到连接释放报文段后,需要发出确认,ACK=1,seq=u+1(因为第一个释放请求已经消耗掉一个序号),ack=w+1。进入TIME-WAIT(时间等待)状态。(需要注意的是此时TCP连接没有真正释放掉,需要经过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态,MSL称为最长报文寿命)

问题?为什么A在TIME-WAIT状态必须等待2MSL的时间呢?

第一:保证A最后发出的ACK报文段能够到达B。由于存在丢失的可能,所以B可能收不到这个确认报文,所以会尝试重传这个FIN+ACK报文段,而如果A能在2MSL时间内收到再发一次ACK报文段,重新启动2MSL计时器。最后A和B都能正常关闭。

第二:A在发送完最后一个ACK报文段后,经过2MSL时间,会将所有本连接中产生的所有报文都从网络中消失。保证下一个新的连接中不会出现这种旧的连接请求报文段。

额外的保障

保活计时器:解决客户端机器突然宕机的场景。服务端在每收到一次客户数据时,重新设置保活计时器,通常是2小时。若2小时没有收到客户数据,服务器就会发送一个探测报文段,以后每隔75S发送一次,若一连发送10个探测报文段后仍无客户的响应,则服务端认为客户端故障,关闭这个连接。

1. 三次握手中如果第二次不握手会怎么样?

首先我们来看下在第二次握手时客户端处于什么状态:

客户端:SYS-SENT,此时客户端在等待服务端的反馈,如果超时,则会进入CLOSE状态(可能期间会重发SYN包,这点不确定,我没去尝试模拟)。

2. 三次握手中如果第三次握手失败怎么样?

第三次握手失败,下图58行服务端会发送RTS报文给客户端,然后服务端进入CLOSED状态,但是是在超时的基础上(30s-2分钟),因此DDos攻击其实就是利用了这短暂的间隙,不进行第三次确认链接,让服务端保持这一次握手导致越积越多最终没法正常处理正常的请求。SYN Flood

最后补充下TCP/IP的状态变更记录:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值