我是目录
- TCP报文段首部格式
- TCP的三次握手
- 举两个栗子
- TCP的四次挥手
TCP的三次握手和四次挥手,可以说是老生常谈的经典问题了,通常也作为各大公司常见的面试考题,我觉得想要清楚理解,还是要从TCP报文段首部格式说起
TCP的介绍
传输控制协议(TCP,Transmission Control Protocol)是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议,
TCP报文段首部格式
首部固定部分各栏位意义如下:
①源埠和目的埠 : 各占2个位元组,分别写入源埠和目的埠,
② 序号 :占4字节,序号范围是【0,2^32 - 1】,共2^32(即4294967296)个序号,在TCP连接中传送的字节流中的每一个字节都按顺序编号,本栏位表示本报文段所发送资料的第一个位元组的序号
例如,一报文段的序号是201,而接待的资料共有100字节,这就表明:本报文段的资料的第一个位元组的序号是201,最后一个字节的序号是300,显然,下一个报文段(如果还有的话)的资料序号应当从301开始,即下一个报文段的序号栏位值应为401,这个栏位的序号也叫“报文段序号”,
③ 确认号 :占4字节,是期望收到对方下一个报文段的第一个资料字节的序号,
例如,B正确收到了A发送过来的一个报文段,其序号栏位值是501,而资料长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的资料,因此,B期望收到A的下一个资料序号是701,于是B在发送给A的确认报文段中把确认号置为701,注意,现在确认号不是501,也不是700,而是701,
简而言之:若确认号为= N,则表明:到序号N-1为止的所有资料都已正确收到,
④资料偏移 : 占4位,它指出TCP报文段的资料起始处距离TCP报文段的起始处有多远,这个栏位实际上是指出TCP报文段的首部长度,由于首部中还有长度不确定的选项栏位,因此资料偏移栏位是必要的,但应注意,“资料偏移”的单位是32位字(即以4字节的字为计算单位),由于4位二进制数能表示的最大十进制数字是15(最大的四位二进制1111
),因此资料偏移的最大值是60字节,这也是TCP首部的最大字节(即选项长度不能超过40字节因为有20字节的固定首部),
⑤紧急URG: 当URG=1时,表明紧急指标栏位有效,它告诉系统此报文段中有紧急资料,应尽快发送(相当于高优先级的资料),而不要按原来的排队顺序来传送,
例如,我们发送档案好好的,突然接收方说我没办法接受档案了,快停止,发送方收到信息就会赶快停止,发送方叫停需要发送命令,就会进入TCP快取中,因为我们的URG设定为1,就需要尽快发送,说白了就是允许插队,不用去排队
当URG置为1时,发送应用行程就告诉发送方的TCP有紧急资料要传送,于是发送方TCP就把紧急资料插入到本报文段资料的最前面,而在紧急资料后面的资料仍然是普通资料,这时要与首部中紧急指标(Urgent Pointer)栏位配合使用,
⑥确认ACK(ACKnowledgment): 仅当ACK = 1
时确认号栏位才有效,当ACK = 0
时确认号无效,TCP规定,在连接建立后所有的传送的报文段都必须把ACK置为1,
⑦推送 PSH(PuSH) :当两个应用行程进行交互式的通信
时,有时在一端的应用行程希望在键入一个命令后立即就能收到对方的回应,在这种情况下,TCP就可以使用推送(push
)操作,这时,发送方TCP把PSH置为1,并立即创建一个报文段发送出去,接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用行程,而不用再等到整个快取都填满了后再向上交付,
⑧复位RST(ReSeT) :当RST=1时,表名TCP连接中出现了严重错误(如由于主机崩溃或其他原因
),必须释放连接,然后再重新建立传输连接,RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接,
⑨同步SYN(SYNchronization) : 在连接建立时用来同步序号,当SYN=1而ACK=0时,表明这是一个连接请求报文段,对方若同意建立连接,则应在回应的报文段中使SYN=1和ACK=1,因此SYN置为1就表示这是一个连接请求或连接接受报文,(后面三次握手的时候具体来看
)
⑩终止FIN(FINis):用来释放一个连接,当FIN=1时,表明此报文段的发送发的资料已发送完毕,并要求释放运输连接,(后面四次挥手的时候具体来看
)
视窗 :占2字节,视窗值是【0,2^16-1】之间的整数,视窗指的是发送本报文段的一方的接受视窗(而不是自己的发送视窗
),视窗值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的资料量(以字节为单位),之所以要有这个限制,是因为接收方的资料快取空间是有限的,总之,视窗值作为接收方让发送方设定其发送视窗的依据,
例如,发送了一个报文段,其确认号是701,视窗栏位是1000.这就是告诉对方:“从701算起,我(即发送方报文段的一方)的接收快取空间还可接受1000个位元组资料(字节序号是701~1700),你在给我发资料时,必须考虑到这一点,”
简而言之:视窗栏位明确指出了现在允许对方发送的资料量,视窗值经常在动态变化,
检验和 :占2字节,检验首部+资料
,检验时要加上12B伪首部,第四个栏位为6
紧急指标 :占2字节,紧急指标仅在URG=1
时才有意义,它指出本报文段中的紧急资料的字节数(紧急资料结束后就是普通资料
) ,因此,在紧急指标指出了紧急资料的末尾在报文段中的位置,当所有紧急资料都处理完时,TCP就告诉应用程序恢复到正常操作,值得注意的是,即使视窗为0时也可以发送紧急资料
,
选项 (长度可变):最大报文段MSS,视窗扩大
,时间戳,选择确认;
TCP连接管理
TCP连接传输三个阶段
TCP连接的建立采用客户服务器方式(c/s)
,主动发起连接建立的应用行程叫做客户
,而被动等待连接建立的应用行程叫服务器
TCP的三次握手
TCP的三次握手
刚开始客户端和客户端都处于关闭的CLOSED状态,先是服务端主动监听某个埠,处于LISTEN状态
ROUND 1:客户端会随机初始化序列号 ISN(c)对应上图的seq=x
将序列号置于TCP首部的【序号】栏位中,同时把SYN标志位置为1,表示SYN报文,接着把第一个SYN报文发送给服务器端,表示服务器发起连接,之后客户端处于SYN_Send 状态,
注意:该报文不包括应用层资料 并且此时的ACK是为0,因为客户端此时没有收到服务器端发出的报文段因为此时客户端不知道期待什么所以确认号是没意义的 ,前面我们也说过了,只有接受请求报文和确认请求报文SYN才为1
ROUND 2::服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)对应上图的seq=y
,同时会把客户端的 ISN + 1 对应上图的ack=x+1
作为 ack的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态,
注意:该报文不包括应用层资料 ,因为我们说过了SYN两种情况下才为1,分别是连接请求和连接请求的确认,所以我们现在是连接请求的接受SYN就是1,从二次握手以后连接,已经建立好了,就不需要SYN了,接下来的连接SYN都为0,当连接建立以后ACK为1,我们的确认号ack就有效了,之所以ack=x+1,就是因为我们接下来期待的收到的下一个栏位为发送端之前发送的X栏位+1
ROUND 3::客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态
,
服务器收到 ACK 报文之后,也处于 establised 状态
,此时,双方以建立起了链接,
Ps:
(1)SYN=1
表示该报文不携带资料,但消耗一个序号 seq=x,seq=x是客户端的初始化序列号,因为tcp是面向字节流的
(2)SYN=1 表示该报文不携带资料,但消耗一个序号 seq=y,seq=y是服务器的初始化序列号,ACK=1
是一个确认号
ack=x+1
,表示服务器下次接收到的序号希望是x+1
,然后服务器进入到SYN-RCVD
等待的状态
(3)ACK=1是一个确认号,seq=x+1是上一次服务器回应的序号要求,ack=y+1
表示客户下一次接收到的序号希望是y+1
tcp通信需要确保双方都具有资料收发的能力,得到ACK回应则认为对方具有资料收发的能力,因此双方都要发送SYN确保对方具有通信的能力,第一次握手
是客户端发送SYN,服务端接收,服务端得出客户端的发送能力和服务端的接收能力都正常;第二次握手
是服务端发送SYN+ACK,客户端接收,客户端得出客户端发送接收能力正常,服务端发送接收能力也都正常,但是此时服务器并不能确认客户端的接收能力是否正常;第三次握手
客户端发送ACK,服务器接收,服务端才能得出客户端发送接收能力正常,服务端自己发送接收能力也都正常,
大白话来谈TCP的三次握手
举两个栗子
村里有个贫困的人叫老许,一直单身没有物件,这一天好友老王来给他介绍物件,但是老许还在睡觉
老王:老许!老许!我是老王,你能听到吗?
老许猛的惊醒一听是老王的声音:老王!老王!我是老许,我能听到你说话,你能听到我说话嘛!!
老王一听,嗯,这是老许的声音:老许!我能听到,我给你说个事,
“老许你要老婆不要!”
老许连忙穿上衣服,激动的跑出门了,
上面就是简单的三次握手建立连接然后传输资料的程序,是不是很有趣!!
再来个栗子:
我们大家都写过情书,我们要怎么知道对方的答案就要经历这些
将小明当作客户端,小红当作服务器端,两人写信告白:
第一次握手:
小明写信告诉小红:我喜欢你很久了,可不可以和我在一起,
第二次握手:
小红收到信以后写信告诉小明:我知道了,其实我也喜欢你,
此时小红并不确定小明是否收到了告白信(因为我们的表白信在传送的时候可能被那些传信的人,拦截了,你们上学的时候遇到这样的嘛!哈哈
),然后就等待
第三次握手:
小明打开信很开心回信:我知道了,那我们在一起吧,
此时才真正建立恋爱的关系,
这样你才算和对方完成,男女朋友才经常做的事情,别想太多,就是腻歪腻歪!!!!!
看到这里不知道大家有啥疑惑没有,如果没有我们来看看这个问题
①为什么是三次握手?不是两次,四次?
我们学完了可能就会说,因为三次握手才能保证双方具有接收和发送的能力,emmmm,这样说好像是没毛病,但是比较片面,并没说出主要的原因
主要原因:是防止失效的连接请求报文段被服务端接收,从而产生错误,
注意:失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是『失效的』,
a. 若建立连接只需两次握手,客户端并没有太大的变化,仍然需要获得服务端的应答后才进入ESTABLISHED状态,而服务端在收到连接请求后就进入ESTABLISHED状态,
此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接,此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送资料或主动发送资料,但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源,
采用“三次握手”的办法可以防止上述现象发生 ,例如上述情况,客户端没有向服务器端的确认发出确认,服务器由于收不到确认,就知道客户端并没有要求建立连接,
②三次握手可以携带资料吗?
第一次、第二次握手不可以携带资料,而第三次握手是可以携带资料的,假设第一次可以携带资料,如果有人恶意攻击服务器,每次都在第一次握手中的SYN报文放入大量资料,重复发送大量SYN报文,此时服务器会花费大量存储器空间来缓冲这些报文,服务器就更容易被攻击了
TCP的四次挥手
在介绍“四次挥手之前先看个例子”
举个栗子
还是上面的小明和小红,现在他们两个处于热恋状态
恋爱之后,小明和小红经常打电话煲电话粥,依旧将小明当作客户端
,小红当作服务器端
,小明跟小红说话,
第一次挥手:
小明说:我说完了,也不早了,该睡觉了,
第二次挥手:
小红还不想睡还想继续说:好的,我知道了,我还没说完,
小红继续吧啦吧啦,说完情话之后
第三次挥手:
小红告诉小明:我说完了,
第四次挥手:
小明收到后告诉小红:好的,我知道了,但是小明也不舍得挂电话,等了2MSL之后小明才挂断了,
如果此时小红说完,等了2MSL,小明一直不出声,这个时候就会重新说一次:我说完了,直到收到小明最后的回复,才挂断电话,
那么我们回归TCP的"挥手”
ROUND 1:
客户端打算关闭连接,此时发送一个TCP首部FIN标志位被设定为1的报文,也就是FIN报文,之后客户端进入FIN_WAIT_1状态
ROUND 2:
服务器收到该报文以后,就向客户端发送ACK应答报文,接着服务器进入CLOSE_WAIT状态,这样客户端到服务器这个方向的连接就释放了–半关闭状态,此时客户端器不用给予回复,因为主机已经结束通话了,只需要等到服务器客户端告诉自己他也要结束
ROUND 3:
服务器端发完资料,就会发出连接释放报文段,主动关闭TCP连接,之所以第二次和第三次的ack是一样的,是因为客户端没有发送资料,所以ack期待的下一个报文段不变
ROUND 4:
客户端回送一个确认报文段,在等到时间,再等到时间等待计时器设定的2MSL(最长报文段寿命)后,连接彻底关闭
看到这里不知道大家有啥疑惑没有,如果没有我们来看看这些问题
①为什么我们第一次连接已经释放了,可是最后还能回送一个报文段那?
这个问题是我在学习的程序中,弹幕上提到的问题,我也有些疑惑其实,断了连接只是不发送资料而已,但是对服务器还是要回复的,在CLOSED状态之前,都不能算是真正的关闭
② 为什么客户端发送ACK之后不直接关闭,而要等待一阵子才关闭
这个是面试的高频考点,这其中的原因就是,要确保服务器是否已经收到了我们的 ACK 报文,如果没有收到的话,服务器会重新发 FIN 报文给客户端,客户端再次收到 ACK 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文,至于 TIME_WAIT 持续的时间至少是一个报文的来回时间
,一般会设定一个计时,如果过了这个计时没有再次收到 FIN 报文,则代表对方成功就是 ACK 报文,此时处于 CLOSED 状态
,
0 评论