三次握手和四次挥手
TCP报头

TCP协议和UDP协议
我们常用的网络通讯、视频聊天、浏览网页......都是通过TCP和UDP这两种协议进行数据传输的
那这两种协议是如何工作的呢?以及它们的区别是什么?
相同:
- 都是在传输层工作
- 目标都是在程序之间传输数据,其中数据可以是文本文件,也可以是视频,也可以是图片,对于TCP和UDP来说,这些数据都是一堆二进制数,没有多大的区别
不同:
连接方式:
TCP基于连接,而UDP基于非连接
如何理解“连接”和“非连接”?
我们可以把“连接“当作“打电话”,把”非连接“当作“写信”
打电话肯定是有求并应,对方接了电话或者没接电话,你都知道情况
如果是写信的话,对面收到或者没收到,你都不知道情况。

TCP是如何保证以上过程的运行?
分别为3个步骤:
- 三次握手
- 传输确认
- 四次挥手
-
三次握手是建立连接的过程:
流程图:

在三次握手中使用的字段:
32位序列号 seq:表示的是本次报文发送的数据的第一个字节的序号。
32位确认号:ack 表示期望下一次应该接受到的报文的第一个字节的序号,若ack = N则表示,到序号N-1为止的所有的数据都已经正确的收到了。
ACK位(ACK大写表示ACK位,ack小写表示确认号):确认,当ACK = 1是确认号ack才有效,建立连接后,所有传送的报文段都必须把ACK置为1.
SYN位:同部位,在建立连接的时候使用,若SYN=1,ACK=0,则表示是一个连接请求报文,若接收方同意接收连接,则使用SYN = 1,ACK = 1。
所以,从上面可以看出来SYN = 1表示这个报文是一个连接请求或连接接收报文。
先理解一下标志位的含义:
- SYN=1 :表示请求建立连接
- SYN=0 :表示连接关闭或者连接请求被拒绝
- ACK=0 :表示不对数据进行确认(这里是A向B请求连接,而不是A向B确认数据,因为B没有对A发送数据,所以ACK=0)
- ACK=1 :表示已接受并确认了上一个数据包
第一次握手(A发送连接请求): A发送请求连接时,将SYN置为1,ACK置为0,seq(初始序列号)取一个随机数x(出于安全着想,防止黑客伪造序列号进行攻击,也可以防止旧连接的干扰(网络堵塞的情况
下))这个过程将消耗一个序号。(图片上ack=0未显示出来)
第二次握手(B确认连接) : 如果B同意A的请求连接,则在B发送的报文中,SYN=1,ACK=1,seq取一个随机数y,ack=x+1,这个过程也消耗一个序号。
这里的seq取y和前面的过程是没有关系的,
ack=x+1,是因为A发送的数据中seq=x,而在发送的过程中消耗了一个序号,所以下一次收到的数据的地址应该为x+1,加的1就是消耗的一个序号
第三次握手(A确认) : A需要再次确认,SYN=0(只是确认,前面已经发送连接请求了所以SYN=0),ACK=1,seq=x+1,ack=y+1,seq表示发送的数据的序号是x+1,
同时希望B下一次发送数据的序号是y+1.
这个过程发了3包数据包,所以也叫做三次握手
问题1:为什么要3次握手而不是2次握手,在服务端发送(SYN+ACK)包的时候,连接不就建立了吗?
答:第三次握手其实是为了防止已经失效的请求报文突然又传到服务端从而引起错误
假设如果只有2次握手,客户端向服务端发送一个SYN包(SYN1)来请求建立连接,但是由于某个未知原因,这个(SYN1)包并没有到达服务端,而是在中间某个网络结点产生了滞留
为了建立连接,客户端会重新发送SYN包(SYN2),这次的数据包正常到达服务端,服务端回复(SYN+ACK)包之后建立连接,但此时第一次发送的SYN包(SYN1)突然恢复,又送
达到服务端,这是服务端会误以为是客户端又发起了一次新的连接请求,从而2次握手之后进入等待数据状态(等待数据状态:两者成功建立连接之后,双方之间发送的数据,服务端等客
户端发数据,客户端以为没有连接,自然就不会发数据给服务端了,所以导致很多网络资源就浪费掉了),也就是服务端会认为是2次连接,而客户端认为是1次连接,造成状态不一致,
所以如果在第三次握手的情况下,服务端没有收到最后的ACK包,自然会认为连接不成功,也就是服务端会认为只有1次连接,正好与事实一致,这就是为什么要有第三次握手,本质上,
是为了解决网络信道上不可靠的问题。
问题2:如何解决丢包问题、乱序问题?
答:TCP的数据包头格式中有2个概念。
-
Sequence Number是数据包的序号,用来解决网络包乱序(reordering)问题。
-
Acknowledgement Number就是ACK——用于确认收到,用来解决不丢包的问题。
- 位码即tcp标志位,有6种标示:
- SYN(synchronous建立联机)
- ACK(acknowledgement 确认)
- PSH(push传送)
- FIN(finish结束) RST(reset重置)
- URG(urgent紧急)
- Sequence number(顺序号码)
- Acknowledge number(确认号码).
乱序问题解决:
SeqNum 的增加是和传输的字节数相关的, TCP 传输数据时,A主机第一次传输1440个字节,seq=1,那么第二次时seq = 1441,B拼接数据就是根据seq进行拼接的,seq数字不断累加避免了乱序.
丢包问题解决:
B主机收到第一次数据包以后会返回ack = 1441. A主机收到B的ack = 1441时,就知道第一个数据包B已收到.
如果B没有收到第一次的数据包,那么B再收到A的数据包时,他就会发ack = 1回去,
A收到B的回复,发现B没有收到第一次数据包,就会重发第一次数据包,这样就可以防止丢包.
还有个问题:在这个过程中,客户端和服务端的初始序列号(x和y)为什么要求不一样?
参考:https://www.cnblogs.com/xiaolincoding/p/15783901.html
- 四次挥手:
客户端和服务端都可以发起断开连接的请求,下面例子以客户端向服务端发送断开连接请求为例
- 第1次挥手:客户端向服务端发送一包FIN包,表示要关闭连接,自己进入终止等待1状态
- 第2次挥手:服务端收到FIN包,向客户端发送ACK包,表示自己关闭等待状态,客户端进入终止等待2状态
服务端此时还可以发送未发送的数据,而客户端此时也还可以接受数据
- 第3次挥手:等服务端发送完数据之后,向客户端发送FIN包,进入最后确认状态
-
第4次挥手:客户端收到FIN包后,回复ACK包,进入超时等待状态,经过超时时间后关闭连接,而服务端收到ACK包后立即关闭连接
解释一下:为什么要客户端要进入超时等待状态?
答:为了确保对方已经收到ACK包,如果客户端发送完ACK包就立即断开连接,一旦ACK包在网路上丢失,服务端将一直停留在最后确认状态,
无法正常关闭。反之,如果客户端在发送完最后一包ACK包后等待一段时间,这时候服务端因为没有收到ACK包会重新发FIN包,客户端此时会
重发ACK包并且刷新超时时间,这个机制和三次握手差不多,也是为了保证在不可靠的网络链中,进行可靠的连接断开。

参考:
https://cloud.tencent.com/developer/article/1114588




浙公网安备 33010602011771号