TCP三次握手四次挥手详解

一、TCP报文首部(部分)

序列号seq序列号。根据序列号识别某个操作。占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。

确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。

确认ACK确认信号。占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效

同步SYN请求建立连接。连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。

终止FIN希望断开连接。用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接

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

专有名词:
SYN(synchronous 建立联机)
ACK(acknowledgement 确认)
PSH(push 传送)
FIN(finish 结束)
RST(reset 重置)
URG(urgent 紧急)
Sequence number(顺序号码)
Acknowledge number(确认号码) ack
establish 建立,创建

二、三次握手理解

三次握手(Three-Way Handshake)即建立 TCP 连接,是指建立一个 TCP连接时,需要客户端和服务端总共发送 3 个包以确认连接的建立。

  1. 第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,seq为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
  2. 第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置ack为x+1(seq+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,seq为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
  3. 第三次握手:客户端收到服务器的SYN+ACK报文段。然后将ack设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

完成了三次握手,客户端和服务器端就可以开始传送数据。

三、四次挥手理解

所谓四次挥手(Four-Way Wavehand)即终止 TCP 连接,就是数据传送完毕,要断开一个 TCP连接时,需要客户端和服务端总共发送 4 个包以确认连接的断开。

  1. 第一次挥手:主机1(可以使客户端,也可以是服务器端)发出连接释放报文,并且停止发送数据,FIN=1,其序列号为seq=u,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了; TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

  2. 第二次挥手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,ACK=1,ack=u+1(seq+1);主机1进入FIN_WAIT_2状态, 客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间

  3. 第三次挥手:主机2向主机1发送FIN报文段(连接释放报文),请求关闭连接,FIN=1,ack=u+1,此时,主机2就进入了LAST-ACK(最后确认)状态,等待客户端的确认

  4. 第四次挥手:主机1收到主机2发送的FIN报文段(连接释放报文),向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间,2MSL时间后依然没有收到回复,则证明Server端已正常关闭,才进入CLOSED状态。可以看到,服务器结束TCP连接的时间要比客户端早一些。

四、Python中TCP网络应用程序开发

在这里插入图片描述
在 socket 编程中,三次握手这一过程由客户端执行 connect 来触发

#客户端代码
#客户端首先发起请求连接服务器
import socket
host = '127.0.0.1'#设置ip
port = 8088 #端口
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((host,port))#连接服务端,三次握手触发

在socket编程中,四次挥手这一过程由客户端或服务端任一方执行 close 来触发

#服务器端代码
import socket
host = '127.0.0.1'#设置ip
port = 8088 #端口
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#连接服务端
s.bind((host,port))
s.listen(5)
print("服务端已开启,等待客户端连接...")
conn, addr = s.accept()#连接
print("客户端已连接...\n")

五、常见面试题

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

【问题3】为什么不能用两次握手进行连接?

答:为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
举一个例子:
"已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。"这就很明白了,防止了服务器端的一直等待而浪费资源。

【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

参考:https://blog.csdn.net/qq_38950316/article/details/81087809

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值