太难了,救救孩子吧,到现在还搞不懂TCP的三次握手四次挥手(1)

2、目标端口:接收方端口

前面我们说到TCP是端到端的,这里就能很好的体现了!每个数据包中都有发送方和接收方的端口。这里每个端口占用2个字节(16位)。

第二行、第三行:

1、序号:tcp是面向字节流的,数据分块在缓存存放及发送,序号用来标记某个数据包最开始的字节是整个数据的第多少个字节。

2、确认号:每次收到请求后,接收方都会回复发送方,告诉对方自己已经接收了多少字节,下一个数据包需要从第多少字节开始发送。这里的值一般等于接收到的序号+接收到的数据包数据部分长度。

这里的序号和确认号是保证TCP可靠特性所不可或缺的,我们后面会通过抓包来详细分析!序号和确认号分别都占用了4个字节(32位)!

第四行:

1、数据偏移:这里叫头部长度更为合适。前面说过TCP头部长度有部分是可变的,所以需要标识数据包数据部分从哪里开始。这个值占用了4位。

2、保留:未使用,供扩展使用。这个值占了3位。

3、标志:标志一共有9个,每个标识占1位,共占9位。上面的抓包截图就能看到这9个标识位!

3.1、NS:Nonce,与ECN显式拥塞通知相关。

3.2、CWR:CWR 标志与后面的 ECE 标志都用于 IP 首部的 ECN 字段,ECE 标志为 1 时,则通知对方已将拥塞窗口缩小

3.3、ECE:ECN-Echo,若设置了该标识,则会通知对方,从对方到这边的网络有阻塞。

3.4、URG:Urgent,用于在发送方加塞。比如在下载文件的时候,下到一半了需要停止下载,就需要发送一个紧急的请求告诉对方停止发送数据。数据包不排队。

3.5、ACK:Acknowledgment,标记为一个确认。

3.6、PSH:Push,与URG对应的,用于接收方加塞。

3.7、RST:Reset,表示出现严重差错,可能需要重新创建TCP连接。如果我们打开某个网站一直没刷出来,我们F5进行刷新,那之前的数据包就要拒绝。

3.8、SYN:用于同步,建立请求的时候用。在握手时候会带这个标记!

3.9、FIN:通信结束,释放连接的时候用。在挥手时候会带这个标记!

4、窗口:不管是发送方还是接收方,都有对应的发送窗口和接收窗口。在通信之前,通信双方会协商窗口的大小。发送方按照接收方的接收窗口设置自己的发送窗口,同时发送窗口还受拥塞窗口的限制,这个在拥塞控制部分会提到!在发送过程中窗口会根据接收方的处理能力调整。这个值对TCP的可靠传输及流量控制起了很大的作用!这个值占了16位。

第五行:

1、校验和:用于校验数据包是否完整或者被修改。这个值占了16位。

2、紧急指针:用来标记本报文段中紧急数据的指针,也就是指明了从数据包数据部分的头部到指定位置的数据为紧急数据,只有在设置了标志位URG的时候才起作用。这个值占了16位。

第六行:

1、选项:选项里面也有些重要的数据,我们挑几个讲一下

1.1、MSS:MSS的全称为Maximum segment size,双方协商的每一个报文段所能承载的最大数据长度(不包括文段头)。

1.2、WS:WS的全称为Window scale,也叫窗口因子!是用来调整窗口大小的。前面我们说到过窗口大小的字段,那这个窗口因子又是做什么用的呢?早期的网络带宽、硬件配置都比较差,所以窗口大小最大只预留了16个bit,也就是最大能设置的值为65535。随着硬件和网络的发展,65535已经不能满足。所以就增加了一个WS的选项来扩展!如果设置了WS,那实际的窗口大小就等于窗口大小乘以窗口因子。

1.3、SACK:SACK的全称为Selective ACK,选择性确认是建立在累计确认(后面讲) 的基础上的!只有收到失序的分组时才会可能会发送SACK,如果接收方接收到了后面的数据包,而发现前面的数据包丢失,则会通知发送方哪些报文段丢失,需要重发!

2、填充:这个字段是为了让整个头部为4个字节的倍数。java中也有很多类似的用法!

我们找到一个数据包,看看其详细的头部数据:

1、红色部分显示了TCP头部的长度为32byte,以及选项部分为12byte。前面我们说了TCP首部固定长度为20byte,所以20+12=32。

2、黄线部分的窗口大小为259byte,窗口因子为256。所以实际的窗口大小为259*256=66304!

面向连接怎么理解


从我表白失败的例子就能看到,我还未确保连接的正常就开始表白,导致我说完了对方却因为信号不好没有听到。如果我事先确保连接正常,就不会出现这样的情况了!我们前面说了TCP是面向连接的,那TCP是怎么面向连接的呢?

三次握手交代了什么?

没错,都是从握手开始!我们都知道,tcp建立连接需要经过三次握手,那每次握手都交代了什么呢?如果只进行两次握手行不行?我们先看一个电话接通的场景:

A:你好,你能听到吗?

B:我能听到,你能听到吗?

A:我也能听到。

在正式通话之前,为了确保通话的可靠,往往都需要经过上面的三次对话进行确认。那这三次对话是必须的吗?每一次对话的必要性又是什么呢?

A:你好,你能听到吗?(让B知道A能说话)

B:我能听到,你能听到吗?(让A知道B能听到,且能说话)

A:我也能听到。(让B知道A能听到)

只有经过三次的对话,才能确认自己的声音能被对方听到且能听到对方的声音。这也才能开展后续的对话。这里我们就不得不祭出经典的三次握手图了:

我们分析三次握手过程及每次握手后的状态如下:

1、A主机发送标识SYN=1(SYN表示A请求跟B建立连接,前面在讲TCP头部时候有说到过),序号Seq=x,第一次握手请求发送后A的状态为SYN_SENT,B在接收到请求后状态由LISTEN变为SYN_RCVD!

2、B主机收到连接请求后向A主机发送标识SYN=1,ACK=1(SYN表示B请求跟A建立连接,ACK表示对A的连接请求进行应答),序号Seq=y,确认号Ack=(x+1),A接收到B的确认后,状态变为ESTABLISHED,B的状态依然为SYN_RCVD!

3、主机A收到后检查Ack是否正确,若正确,则发送标识ACK=1(表示对B的连接请求进行应答),序号Seq=(x+1),确认号Ack=(y+1)。B接收到A的确认后,A和B的状态都变为ESTABLISHED!

这里我们要注意的几点是:

1、图中的发送请求中中括号里面的SYN、ACK就是前面说TCP头部中的那几个标志位!而Seq和Ack分别代表序号和确认号。

2、接收方在接收到发送方发送的Seq后,应答一个Ack,Ack的值等于Seq+1,表示已要发送方开始发送Seq+1位置的数据。

2、B在接收到了A的连接请求后回复中同时发送了SYN、ACK两个标识位,将建立连接的请求和对A的应答在同一个包中发送了,这也是为什么只需要三次握手,就能建立连接。

我们依然向www.17coding.info发送请求,下面为三次握手的包:

在info那一栏,我们很明显的能看到发送的数据包头部有我们上面说到的那些标志位,还有Seq、Ack等头部信息,还有Win、MSS等头部选项数据!因此三次握手不仅仅是单纯建立连接,还会协商一些参数!

当我鼠标选择某一行时,如果这个数据包包含了对某个数据包的确认(也就是有ACK的标记),就能在对应的数据包的No列上面看到一个小勾勾,比如上面图中我鼠标选择的是第三次握手的数据包,在第二次握手的数据包前面就有个小勾勾。

为什么握手只需要三次而挥手需要四次?

通过三次握手,双方就建立了一个可靠的连接,就能进行数据的传输了!当数据传输完成,就得将连接关闭,因为连接也是一种资源!连接的关闭需要经过四次挥手!

为什么握手可以三次完成,但是挥手却需要四次呢?我偏要三次行不行?其实也没啥不可以的!比如下面的对话场景:

A:我说完了,你说完就挂电话吧!

B:好嘞,我也说完了,可以挂电话了!

A:好嘞,拜拜。

挂断…

这样三次对话就可以实现挥手了,但是在实际的网络中,当我发出一个请求的时候,可能服务器的响应体比较大,需要较长时间的传输!所以当客户端主动发起断开请求的时候,服务器先回应一个确认,等所有数据传输完毕后再发送服务器断开的请求。

A:我说完了,你说完就挂电话吧!

B:好嘞…

B:…

B:我也说完了,可以挂电话了

A:好嘞,拜拜

挂断…

所以大部分情况下都需要进行四次挥手!但是,在我个人的抓包实践中,也会有三次挥手就能完成断开连接的情况。

这里我们又不得不祭出经典的四次挥手图了:

我们分析四次挥手过程及每次挥手后的状态如下:

1、主机A发送标识FIN=1(FIN表示A请求关闭连接)用来关闭A到B的数据传输。此时A的状态为FIN_WAIT_1!

2、主机B收到关闭请求后向A发送ACK(ACK表示应答A的关闭连接请求),A不再向B发送数据。此时A的状态为FIN_WAIT_2,B为CLOSE_WAIT!

3、主机B发送标识FIN=1用来关闭B到A的数据传输。此时A的状态为TIME_WAIT,B为LAST_ACK!

4、主机A收到关闭请求后向B发送ACK,此时B不再向A发送数据。此时A、B都关闭了,状态变为CLOSED。

在图中我们能看到,A的TIME_WAIT状态会持续2MSL再变成CLOSED,MSL(Maximum Segment Lifetime)的中文可以译为“报文最大生存时间”!他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。那TIME_WAIT维持2MSL的作用是什么呢?

1、第4次挥手的时候主机A发送ACK到主机B,如果发送完成后就直接就关闭连接,那如果由于网络原因B没有收到ACK,那B就没法关闭连接了!因此A在回复确认后,还需要等待,万一B没有收到应答还会继续发送FIN的请求。

2、如果不等待2MSL,那客户端的端口可能会被重用,如果再次用这个端口建立与服务器的连接,那前后两个使用相同四元组的的连接之间会形成干扰!

我们看上面向www.17coding.info发送请求的挥手数据包:

可能大家在抓包的时候不能立马看到四次挥手的数据包!那是因为在HTTP1.1及之后,默认都开启了长连接!也就是在一次请求之后,建立的连接并不会立马关闭,而是供后续的其他请求继续使用,以减少每次重新建立连接的资源消耗!如果想发出请求后立马能抓到四次挥手的数据包,可以设置Http的头部Connection:close。这样每次发送请求都能看到完整的三次握手四次挥手的过程啦!

TCP是怎么保证可靠传输的?


保证传输的可靠我们前面已经说到了面向连接,建立连接是保证数据传输的第一步。那在连接建立之后的数据传输怎么保证可靠呢?

我们再次回到我们打电话的场景,一般在对话的过程中,都是得双方都有互动,给与对方回应。而不是一个人一个劲的说而另一方没有任何回应!比如下面场景:

A:跟你讲哦,我上周网上认识了一个妹子

B:嚯,牛逼啊!

A:然后我昨天约出来见面了

B:666啊!然后呢?

A:然后我们@#¥%……&

B:卧槽,你刚刚说啥我没听清,你再说一遍?…

这样的确认和应答就确保了双方的通信能够完整可靠。TCP也采用了这种y应答和确认重传的机制,保证在不可靠的网络上实现可靠的传输。只要我没有收到确认,我就认为没有发送成功,就会重发。

停止等待协议

停止等待协议就是每次给对方发送数据包后,需要等待对方的回应然后再发送下一个数据包!停止等待协议会出现如下几种情况:

1、无差错情况:A发送M1包到B,B收到后会给A一个确认,当A收到B的确认后再发送包M2。

2、超时重传:A发送M1包到B,如果发送过程中包丢失,A会重新发送。A等待重发的时间是比一个报文的往返时间(RTT)稍微多一点。

3、确认丢失:如果B在给A发送确认的时候丢失,A会重新发送M1包给B,由于B已经处理过M1的数据包所以B会丢弃报文,然后重传确认M1给A。

4、确认迟到:如果A发送数据包M1给B,B回复确认的时候延迟了。这时A又会重新发送包M1给B,B收到后丢弃数据包,然后重传确认M1给A。这时A会收到多次确认,当第二次收到迟到的确认后A也会丢弃该确认。

我们从上面能看到,停止等待协议每次都是等到收到确认后再发下一个数据包。只要我没收到你给我的确认,我就认为你没有收到我发的数据包,我就会进行重发!这样虽然可靠,但是会导致信道利用率较低!

流水线传输

流水线传输就是每次发送多组数据包,不必每次发完一组就停下来等待对方的确认。由于信道上一直有数据不间断的传输,因此可以获得较高的信道利用率!

流水线传输如何保证可靠的呢?需要发送方维持发送窗口,假如发送窗口是5,那5个数据包会同时发送,然后等确认!如果有收到接收方的确认,窗口就会滑动,进行第6个数据包的发送。

如果都是单个确认,可能效率会比较低,所以有了累计确认!也就是说假如发送方发送了数据包1、2、3、4,接收方只需要回复对数据包4的确认,那表示1234数据包都已经收到了,就可以进行第五个数据包的发送了!假如发送了数据包1、2、3、4,其中第三个数据包丢失,那该怎么确认呢?TCP只会回复对数据包2的确认,并且对数据包4进行选择性确认(TCP头部选项讲到过的SACK),这样发送方就知道数据包4已经成功发送,只需要重发数据包3。

继续前面抓包的例子,接收方并不是对每个数据包都进行确认,而是对多个数据包进行累计确认:

这里我们能看到服务器发送多个数据包后,客户端才进行了一次确认。

流量控制和拥塞控制


通过前面我们知道了,通过建立可靠的连接和确认机制,保证了TCP的连接的可靠!但是每个人使用的计算机的处理能力都是不一样的,我发送太快了对方处理不过来怎么办呢?通信双方怎么去协调发送和接收数据的频率呢?

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后如何让自己一步步成为技术专家

说句实话,如果一个打工人不想提升自己,那便没有工作的意义,毕竟大家也没有到养老的年龄。

当你的技术在一步步贴近阿里p7水平的时候,毫无疑问你的薪资肯定会涨,同时你能学到更多更深的技术,交结到更厉害的大牛。

推荐一份Java架构之路必备的学习笔记,内容相当全面!!!

成年人的世界没有容易二字,前段时间刷抖音看到一个程序员连着加班两星期到半夜2点的视频。在这个行业若想要拿高薪除了提高硬实力别无他法。

你知道吗?现在有的应届生实习薪资都已经赶超开发5年的程序员了,实习薪资26K,30K,你没有紧迫感吗?做了这么多年还不如一个应届生,真的非常尴尬!

进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!

【关注】+【转发】+【点赞】支持我!创作不易!
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
你的薪资肯定会涨,同时你能学到更多更深的技术,交结到更厉害的大牛。

推荐一份Java架构之路必备的学习笔记,内容相当全面!!!

[外链图片转存中…(img-6mlkTSHH-1712425113770)]

成年人的世界没有容易二字,前段时间刷抖音看到一个程序员连着加班两星期到半夜2点的视频。在这个行业若想要拿高薪除了提高硬实力别无他法。

你知道吗?现在有的应届生实习薪资都已经赶超开发5年的程序员了,实习薪资26K,30K,你没有紧迫感吗?做了这么多年还不如一个应届生,真的非常尴尬!

进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!

【关注】+【转发】+【点赞】支持我!创作不易!
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值