Linux——TCP协议(三次握手(从数据包名,双方连接状态,包序管理分析),四次挥手(从数据包名,双方连接状态分析))


前言

TCP协议的连接是面向连接,可靠传输,面向字节流的,而TCP之所以能保持可靠传输是因为三次握手四次挥手

1. 三次握手

1.1 从数据包名称连接双方状态分析三次握手

首先我们通过数据包名连接双方的连接状态来了解三次握手的过程

如下图所示
在这里插入图片描述
客户端在发送SYN数据包后客户端的状态变为SYN_SENT,当服务端接收到客户端发送的SYN数据包后,服务端的状态变为SYN_RECV,当客户端接收到服务端的SYN数据包和ACK数据包后,客户端的状态变为ESTABLISHED,当服务端接收到客户端发送的ACK数据包时,服务端的状态变为ESTABLISHED,此时客户端和服务端已完成三次握手,即建立了双向连接。

【问题一】为什么要三次握手,而两次握手不行呢?

三次握手可以保证通信双方都是有连接的,若只进行两次连接服务端回复客户端的应答并发送SYN数据报,客户端不作出回应,并不能确保客户端接收到来自服务端的数据,因此两次握手只能保证客户端到服务端的连接是有效的,并不能保证服务端到客户端的连接有效

1.2 包序管理

1.2.1 抓网络数据包

  • 在windows平台下,可以使用wireshark软件来抓取网络数据包
  • 在linux平台下,使用 tcpdump 来抓取网络数据,TCP和UDP的包都可以使用此命令抓取

    1)万能公式:tcpdump -i any port [端口] -s 0 -w xxx.dat

    2)使用root用户进行抓包

    如上2)中的命令是对某个端口进行抓包,并将结果放入xxx.dat中,但我们不能直接对xxx.dat中的数据进行分析,需要借助windows平台下的wireshark软件来分析

1.2.2 分析TCP网络数据包

我们之前单进程的客户端和服务端的代码,使用tcpdump抓包分析三次握手的过程

首先在root用户下输入 tcpdump -i any port 18989 -s 0 -w 123.dat ,先进行抓包,再让客户端服务端程序跑起来防止三次握手结束,没有抓到,让客户端服务端跑一会后终止程序,我们可以看到如下图所示:
在这里插入图片描述
可以看到一共抓到了64个数据包,并产生了一个123.dat文件,通过Xftp将123.dat传到windows下使用wireshark进行分析,如下图所示:
在这里插入图片描述

1.2.3 分析TCP包序号

为什么TCP需要包序号?

本质上是为了维护可靠传输,客户端维护了一套序号,服务端也维护了一套序号

  • client–>server:消耗(seq)的是客户端维护的序号,服务端告诉客户端自己收到数据的时候,是确认(ACK)客户端的序号
  • server–>client:消耗(seq)的是服务端维护的序号,客户端告诉服务端自己收到数据的时候,是确认(ACK)服务端的序号

观察如下图所示抓到的包,分析TCP包序号的变化
在这里插入图片描述
分析如下图所示:
在这里插入图片描述

  • 纯ACK数据包不消耗序号
  • TCP数据也消耗序号,一个字节消耗一个序号
  • 确认序号ACK=消息发送方的序号+数据长度
  • 确认序号的作用是:告知消息发送方,期望下次发送数据从哪一个序号开始发送

    注意:TCP三次握手中,协商双方的其实序号并不一定是从0号序号开始,可以从任意位置开始,只要双方协商好就行

    TCP可靠的原因就在于序号,丢了那个数据都可以知道,因为一个字节占一个序号

2. 四次挥手

通过数据包名和连接双方的状态分析四次挥手的过程如下图所示:

在这里插入图片描述
数据传输完毕以后,双方都可以释放连接。在最开始的时候,客户端与服务器都是处于ESTABLISHED状态,如果客户端主动关闭,则服务端被动关闭;若服务端主动关闭,则客户端被动关闭;

MSL:报文的最大生存时间,在传输中,一个报文的最大生命周期就是一个MSL时间,过了这个时间该报文就会被丢弃

【问题一】主动断开方为TIME_WAIT状态为什么要等待2MSL后才变为CLOSED状态呢?

当主动断开方为TIME_WAIT状态时,如果主动断开方发送的ACK数据包丢失,则过MSL后,被动连接方会重新发送FIN数据包,让主动断开连接方重新发送ACK数据包,若主动断开连接方MSL后将状态变为CLOSED则无法收到重发的FIN数据包,无法重新发送ACK数据包
在这里插入图片描述

  • 2MSL = 丢失的ACK的MSL + 重传的FIN的MSL

本质就是为了让主动断开连接方能够接收到被动断开连接方重传的FIN报文

  • TIME_WAIT状态存在于主动断开连接方

如果服务端位于主动断开连接方,此时一定在四次握手的过程中拥有TIME_WAIT状态;即使当服务端进程已经结束了,但是服务端之前使用TCP协议针对针对的连接还是TIME_WAIT状态,换句话说,服务端之前绑定的端口还没有被网络协议栈的TCP协议释放掉,导致服务端无法快速的重启(端口已被站用问题)

解决办法:使用setsockopt函数,让端口重用
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

  • sockfd:侦听套接字listen_fd
  • level:SOL_SOCKET 套接字选项
  • optname:SO_REUSEADDR 重用端口(只有当服务端的状态为TIME_WAIT时才能重用)
  • optval:1
  • optlen:opt的大小

假设客户端主动断开连接,服务端被动断开连接

1)客户端进程发出连接释放报文FIN=1,并且停止发送数据。此时,客户端进入FIN-WAIT1(终止等待1)状态。这时候客户端处于一个半关闭的状态,即客户端已经没有数据需要发送了,但是服务器若要发送数据,客户端依然需要接受。

2)服务器收到连接释放报文后,发送确认报文ACK=1。此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。进入CLOSE_WAIT后说明服务器准备关闭连接。

3)客户端收到服务器的确认请求之后,此时客户端就进入了FIN-WAIT2(终止等待2)状态,等待服务器发送连接释放报文。(在这个之前还需要接受服务器发送的最后的数据)。

4)当服务器真正调用close关闭连接时, 会向客户端发送FIN=1, 此时服务器进入LAST_ACK(最后确认)状态, 等待客户端的最后一次ACK回复。

5)客户端收到服务器的链接释放报文之后,必须发出确认报文ACK=1。此时,客户端就进入了TIME-WAIT(时间等待)状态,等待用户关闭套接字。注意此时TCP链接还没有释放,必须经过2*MSL(报文最大生命周期)的时间后,当客户端撤销相应的TCP后,才进入CLOSED状态。

6)服务器只要收到客户端发出的确认,彻底关闭连接,立即就进行CLOSED状态,于是就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值