三次握手和四次挥手知识总结(超详细)

2022年05月12日 阅读数:5
这篇文章主要向大家介绍三次握手和四次挥手知识总结(超详细),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

前言
最近学习了计算机网络的知识,看了不少的视频,并参考了不少资料,写下了这将近4500字的与“三次握手和四次挥手”相关的知识,但愿能帮助到各位小伙伴儿以及加深本身印象,方便之后复习用
若是有什么写的并不许确的地方,还请大佬不吝赐教web

在这里插入图片描述

TCP报文段的首部格式介绍

在这里插入图片描述

在这里插入图片描述

源端口:占 16位2个字节发起通讯的那个进程面试

目的端口:占 16位2个字节接收通讯的那个进程安全

序号(seq):占 32位4 个字节,序号范围[0,2^32-1],序号增长到 2^32-1 后,下个序号又回到 0。TCP 是面向字节流的,经过 TCP 传送的字节流中的每一个字节都按顺序编号,而报头中的序号字段值则指的是本报文段数据的第一个字节的序号。例如:咱们的seq = 201,携带的数据有100,那么最后⼀个字节的序号就为300,那么下⼀个报⽂段就应该从301开始.服务器

确认号(ack):占 32位4 个字节,指望收到对方下个报文段的第一个数据字节的序号当标志位ACK值为1时,才能产生有效的确认号ack。而且:ack=seq+1;网络

RST:当RST=1时,代表TCP链接出现严重错误,此时必须释放链接,以后从新链接,⼜叫重置位.socket

URG:紧急指针标志位,当URG=1时,代表紧急指针字段有效.它告诉系统中有紧急数据,应当尽快传送,这时不会按照原来的排队序列来传送.⽽会将紧急数据插⼊到本报⽂段数据的最前⾯tcp

ACK:当ACK=1时,咱们的确认序列号ack才有效,当ACK=0时,确认序号ack⽆效,TCP规定:全部建⽴链接的ACK必须所有置为1svg

PSH:推送操做,提示接收端应用程序当即从TCP缓冲区把数据读走函数

SYN:同步序列号标志位,tcp三次握⼿中,第⼀次会将SYN=1,ACK=0,此时表⽰这是⼀个链接请求报⽂段,对⽅会将SYN=1,ACK=1,表⽰赞成链接,链接完成以后将SYN=0学习

FIN:在tcp四次挥⼿时第⼀次将FIN=1,表⽰此报⽂段的发送⽅数据已经发送完毕,这是⼀个释放连接的标志

PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号

16位窗⼝的⼤⼩:win的值是做为接收⽅让发送⽅设置其发送窗⼝⼤⼩的依据.

紧急指针:只有当URG=1时的时候,紧急指针才有效,它指出紧急数据的字节数.

三次握手

在这里插入图片描述
三次握手,顾名思义就是客户端与服务端进行三次通讯。
在这里插入图片描述
刚开始客户端处于关闭(Closed)状态,服务器处于监听(Listen)状态。

第一次握手 : 客户端给服务器发送SYN报文,初始的序列号为x,而且须要消耗一个序号。此时客户端进入SYN_SENT状态。
当SYN=而ACK=时,代表这是一个链接请求报文。
注意SYN=1时的报文段是不能携带数据的,所以第一次握手和第二次握手客户端和服务端都不能携带数据。 这是由于若是能够携带数据的话,假若有人想要攻击服务器,只须要每次在第一次握手时在SYN报文放入不少数据,重复发送这些大量的SYN报文,服务器就会花大量内存缓冲这些报文,服务器就更加容易被攻击了。

第一次握手服务端能够看出 :客户端的发送能力,和本身的接收能力处于正常状态

第二次握手:服务端收到来自客户端的SYN报文后,对这个SYN报文确认后,会把本身的SYN报文响应给客户端,此时ACK=1表示确认序列号有效,SYN=1也不能携带数据,而且确认号(ack)的值为传来的seq+1,即为x+1,此时初始序号为y。此时服务器进入SYN_RECV状态

第二次握手客户端能够看出:服务端的发送和接收能力都正常,客户端的发送和接收能力也都正常,但重要的一点是服务端不知道客户端的接收能力是否正常。

第三次握手:客户端收到了服务器SYN+ACK的包,此时客户端处于ESTABLISHED状态而且客户端和服务端均表示赞成链接,所以会发送一个ACK报文,确认号ack的值仍为序列号+1,即y+1,初始seq值为x,因此第二个报文段seq+1,即x+1。

第三次握手可携带数据,不携带数据则不消耗数据

第三次握手能够看出: 客户端的发送接收,服务端的发送接收能力均正常。

两次握手为何行不通

首先举一个生活中常见的例子:

此时你和你的对象拨通了电话(没对象就本身new一个):
你 :“喂,能听到我说话吗?”
你对象 :“亲爱的,我能够听到!”
此时你忽然不说话了…
在这里插入图片描述

试想一下,你(new 的)对象如今确定怀疑是否是本身的麦克风有问题或者本身的网有问题,致使你听不见…
在这里插入图片描述

所以在这里也是如此,仅两次握手,服务端不知道客户端是否能接收到本身给它的通讯,全部三次握手是可行的。
另外,三次握手是安全的,而且节约资源

若是客户端发送请求时出现了丢包状况,由于本身没发送,又从新传了一遍,然而等数据传输完成后客户端和服务端都释放了链接,第二次传输的数据在释放链接前给服务器传了过去,但第一次传输的数据假如因为网络缘由滞留的时间长了,在释放链接后到达了服务端,这个时候服务端就会误觉得客户端又发出了一次新的请求,服务端确认了客户端第一次发出的报文段并赞成创建了新的链接,发送报文给客户端,此时服务端会一直等待客户端的答复,而客户端此时正处于释放链接状态,因此致使白白浪费了资源。

半链接队列和全链接队列

半链接队列(syn queue)
客户端发送SYN包,服务端收到后回复SYN+ACK后,服务端进入SYN_RCVD状态,此时双方尚未彻底创建链接,这个时候的socket会放到半链接队列。

全链接队列(accept queue)
当服务端收到客户端的ACK后,socket会从半链接队列移出到全链接队列。当调用accpet函数的时候,会从全链接队列的头部返回可用socket给用户进程。全链接队列中存放的是已完成TCP三次握手的过程,等待被处理的链接,在客户端及服务端的状态均为 ESTABLISHED

在这里插入图片描述

四次挥手

四次挥手,顾名思义就是客户端和服务端四个步骤的释放链接,断开链接须要发送四个包,别名链接终止协议。因为TCP链接是全双工的,所以每一个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的链接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP链接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另外一方执行被动关闭。

在这里插入图片描述

刚开始客户端和服务端都处于ESTABLISHED状态,假如客户端主动发起关闭请求:

第一次挥手:TCP客户端向服务端发送一个FIN报文,用来关闭客户端到服务端的数据传送,其中包含一个序列号seq=u,发送完后,客户端进入**FIN_WAIT_1状态,**即主动关闭TCP链接,再也不发送数据,(可是能够接收服务器发来的报文),等待服务端回复。

第二次挥手:服务端接收到FIN报文后,会发回一个ACK,代表本身已经接收到了此报文,(此时客户端接就知道服务端接收到了本身的断开链接请求),(可是服务端可能还有数据要传输),而且seq=v,ack的值为序列号+1,此时服务端进入CLOSE_WAIT关闭等待状态和SYN同样,一个FIN将占用一个序号。这个时候TCP处于半关闭状态,当客户端接收到服务端的回复后,进入FIN_WAIT_2终止等待2状态。

第三次挥手:服务器关闭客户端的链接,发送一个FIN报文给客户端,而且指定一个序列号,ack的值为u+1,此时服务器处于LAST_ACK最后确认状态,等待客户端回应。

第四次挥手 :客户端收到 FIN 以后,同样发送一个 ACK 报文做为应答(ack = w+1),且把服务端的序列值 +1 做为本身 ACK 报文的序号值(seq=u+1,此时客户端处于 TIME_WAIT(时间等待状态)TIME-WAIT状态是为了等待足够的时间以确保远程TCP接收到链接中断请求的确认。

注意 :

这个时候由服务端到客户端的 TCP 链接并未释放掉,客户端须要通过时间等待计时器设置的时间 2MSL(一个报文的来回时间) 后才会进入CLOSED状态(这样作的目的是确保服务端收到本身的 ACK 报文。若是服务端在规定时间内没有收到客户端发来的 ACK 报文的话,服务端会从新发送 FIN 报文给客户端,客户端再次收到 FIN 报文以后,就知道以前的 ACK 报文丢失了,而后再次发送 ACK报文给服务端)。服务端收到 ACK 报文以后,就关闭链接了,处于 CLOSED 状态。

这里解释一下须要等待2MSL的缘由:

一、防⽌客户端最后⼀次发给服务器的确认在⽹络中丢失以⾄于客户端关闭,⽽服务端并未关闭,致使资源的浪费。
  二、等待最⼤的2msl可让本次链接的全部的⽹络包在链路上消失,以防形成没必要要的⼲扰。
  若是客户端t直接closed,而后⼜向服务端r发起了⼀个新链接,咱们不能保证这个新链接和刚关闭的链接的端⼝号是不一样的。假设新链接和已经关闭的⽼端⼝号是⼀样的,若是前⼀次滞留的某些数据仍然在⽹络中,这些延迟数据会在新链接建⽴后到达服务端,因此socket就认为那个延迟的数据是属于新链接的,数据包就会发⽣混淆。因此客户端要在TIME_WAIT状态等待2倍的MSL,这样保证本次链接的全部数据都从⽹络中消失

为何客户端须要TIME_WAIT状态:
假设最终的ACK丢失,服务端将重发FIN,客户端必须维护TCP状态信息以即可以重发最终的ACK,不然会发送RST(TCP链接出现错误),结果服务端认为发生错误。TCP实现必须可靠地终止链接的两个方向(全双工关闭),客户端必须进入TIME_WAIT 状态,由于客户端可能面临重发最终ACK的情形。
在这里插入图片描述

为何四次挥手,三次挥手不行吗

首先为何握手是三次,而挥手是四次:

由于握手的时候并无数据传输,因此服务端的 SYN 和 ACK 报文能够一块儿发送,可是挥手的时候有数据在传输,因此 ACK 和 FIN
报文不能同时发送
,须要分两步,因此会比握手多一步。

其次为何三次挥手不可行:

由于服务端在接收到FIN, 每每不会当即返回FIN ,必须等到服务端全部的报文都发送完毕了,才能发FIN。所以先发一个ACK表示已经收到客户端的FIN,延迟一段时间才发FIN。这就形成了四次挥手。
若是是三次挥手会形成:
若是将服务端的两次挥手合为一次,等于说服务端将ACK和FIN的发送合并为一次挥手,这个时候长时间的延迟可能会致使客户端误觉得FIN没有到达客户端,从而让客户端不断的重发FIN。全部只能第二次握手先发送ACK确认接收到了客户端的数据,等服务器发送完了数据,再发送FIN包进行第三次挥手。

用一个生活中的案例来讲明

前提:假如你在外边玩,此时你拨通了妈妈的电话
1.你:“娘亲俺饿了,能给我作一份香喷喷的合罗面吗”
2.你的妈妈:“好,我如今准备准备,买买菜,等会作好了喊你”
。。。。。。家长作饭的过程。。。。。。
3.你的妈妈:“儿砸,饭作好了,该下面条了,何时回来呀”
4.你:“好嘞妈,你先下面条吧,我正在上楼”
( 。。。。最后,你吃上了香喷喷的合罗面,并表示:妈妈的味道。。。。)

经过此例子,第二个步骤和第三个步骤确定不能合并,由于第二个步骤妈妈肯定了,你饿了,但尚未作好饭,全部等饭作好了(数据发完了),才会通知你一切都准备好了。

文章到这里就结束了,这方面的知识面试的时候问的仍是挺多的,但愿各位各位小伙伴以及我都能把这些知识学透学扎实,面试的时候都不怕。若是您看完了此文章,以为有什么不许确或者须要改进的地方,请大佬指正。或者有什么不懂的地方,均可以提出来,会耐心解答的。

再次感谢各位小伙伴儿
在这里插入图片描述