TCP协议连接管理过程(三次握手和四次挥手过程)

本文主要参考《TCP/IP协议卷1》 和 《图解TCP/IP》
首发地址,本人个人博客

TCP状态管理

TCP状态表

image.png

TCP状态变迁

image.png

建立连接

序列号

TCP在发送SYN包时,会将初始序列ISN设置在TCP头中,应答方回复ACK包时,根据SYN包中的ISN + 1作为应答ack值。后续每次发送数据包后,SN都会递增数据长度的值,当达到 2^32 - 1 后就会折返从0重新开始计算

生成规则:

  • 【RFC0793】指出初始序列由一个32位计数器设置,每4微秒 + 1,

  • 【RFC1948】中指出了另一种随机生成算法
    ISN = M + F(localhost, localport, remotehost, remoteport)。

    • 其中M为一个计时器,计时器每4毫秒 +1

    • F为一个hash算法,根据连接两端的ip 和 port 计算一个hash值

  • linux系统中采用更为复杂的方式:32位中,前面8位是一个随机序列,后面24位由一个hash函数生成。前8位中的5位由一个定时器的数值取模32(2^5)得到,这个定时器64秒加1,接着三位是对服务器最大段的编码值。

为什么随机:
TCP的初始序列号不能被设置为固定值?

  • 一是为了避免由于网络延迟等原因,导致延迟收到上一次连接的数据包而做出错误的响应

  • 二是为了防止被恶意攻击者猜测到后续序列号而恶意攻击。

序列回绕:
当序列号地址到大于 2^32 - 1 后,则会回绕从0重新开始计算,当序列回绕后,应该如何保证数据包的顺序?
在linux内核中判断两个包序列大小的方式:

static inline int before(__u32 seq1, __u32 seq2)
{
return (__s32)(seq1-seq2) < 0;
}

这里的__s32是有符号整型的意思,而__u32则是无符号整型
根据该算法,当折返的序列与前一个序列的增量不超过 2^31-1 时则可以正确排序。
因为此时当seq1 - seq2 > 2^31-1,该32位无符号整数的最高位为1,因此转换为31位有符号整数时,由于最高位为1,因此为负数。

重复序列
当由于发送端重传或者其它原因,接收端收到多个序列重复的包时,会根据时间戳判断,抛弃时间较远的包,保留最近的包

三次握手过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wmiu8PkL-1611067612363)(http://resource.teemor.xyz/1609911695327)]

  • 第一次
    客户端发出第一个SYN包,在TCP头部信息携带初始序号(ISN)、MSS(最大消息长度)、窗口大小等信息。客户端进入 SYN_SENT 状态

  • 第二次
    第二次握手时服务端向客户端发送数据包,包含了SYN和ACK两个标志位,SYN表示服务端发起到客户端的连接,ACK表示响应客户端的连接请求。
    在TCP包头部中也会携带服务端的初始序号,以及响应客户端请求的ACK值(该值为 客户端的 ISN + 1)、MSS、窗口大小。服务端进入 SYN_RCVD 状态

  • 第三次
    客户端收到响应报文后,校验ack值是否正确,然后响应客户端的连接,发送ACK包,ack值设置为 服务端 ISN + 1。服务端收到报文后,校验成功ack,则连接建立成功。客户端和服务端进入 ESTABLISHED 状态,三次握手完成。

主动打开&被动打开

发送第一个SYN的一端将执行主动打开( active open)。接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)

应答序号(ack):用以确认收到的数据包,该值为收到数据包的 seq + len (序列号 + 数据长度),同时也是告诉发送端,我下次需要收到从该值开始的数据包

MSS实际的值是在三次握手时,根据两端主机SYN包头部信息中的MSS值计算得出的,计算方式是选择两端主机中较小的那个MSS值。当TCP传输大量数据时,数据会被分隔成N个MSS大小的数据进行发送。默认值为536字节

SYN和FIN包会占用一个序号,该作用是为了包重传,因为在TCP协议中,只有消息体长度大于0才会有ACK响应

连接超时

如果握手过程中,某个数据包丢包或者一端下线,则会导致握手失败。比如客户端发送了SYN包之后就下线了,此时服务端收到了SYN包,并回复了SYN+ACK包,但是由于客户端下线了,所有服务端不会收到ACK包。此时服务端会进入重试阶段,每隔一定时间没有收到回复则会重新发送包。
在Linux下:
默认重试次数为5次
重试的间隔时间从1s开始每次都翻倍
5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s
第5次发出后还要等32s才知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才会断开这个连接

复位报文

复位报文标志是RST,当发送复位报文时,TCP头部的RST标志位会置为1。收到复位报文的一方不会做出回应,将会直接终止连接。

一般说来,无论何时一个报文段发往基准的连接( referenced connection)出现错误,TCP都会发出一个复位报文段(这里提到的“基准的连接”是指由目的 IP地址和目的端口号以及源 IP地址和源端口号指明的连接。)。—TCP/IP协议卷1

RST报文会有以下几种场景出现:\

  • 向不存在的对端发送连接请求:即当我们向一个没有使用的端口发送连接请求时,TCP则会使用复位。
  • 异常中止连接:连接的一端不通过发送FIN报文进行正常的终止连接。而是选择发送RST报文,并丢弃所有待发送数据。
  • 检测半打开连接:如果一方已经关闭或异常终止连接而另一方却还不知道,我们将这样的 TCP连接称为半打开(Half - Open)的。任何一端的主机异常都可能导致发生这种情况。只要不打算在半打开连接上传输数据,仍处于连接状态的一方就不会检测另一方已经出现异常。半打开连接的另一个常见原因是当客户主机突然掉电而不是正常的结束客户应用程序后再关机

同时打开

两个应用程序同时彼此执行主动打开的情况是可能的,尽管发生的可能性极小。每一方必须发送一个 SYN,且这些SYN必须传递给对方。这需要每一方使用一个对方熟知的端口作为本地端口。这又称为同时打开( simultaneous open)。
image.png

一个同时打开的连接需要交换 4个报文段,比正常的三次握手多一个。此外,要注意的是我们没有将任何一端称为客户或服务器,因为每一端既是客户又是服务器

TCP半关闭

TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。这就是所谓的半关闭。
如果应用程序不调用socket的close而调用shutdown方法时,且第2个参数值为1,则进行的就是半关闭。
如下图所示,就是在客户端进行半关闭后,服务端继续向客户端发送数据的示意图

image.png

关闭连接

当TCP连接断开时,需要两端进行四次数据包的发送才能完成,也就是四次挥手。这是由于TCP的半关闭(half-close)造成的,由于TCP是全双工(数据能在两个方向上同时传递),因此每个方向都需要单独地进行关闭操作。关闭连接由FIN标志位标识\

四次挥手

四次挥手过程如下图所示

image.png
当服务器收到这个 FIN,它发回一个ACK确认序号(为收到的序号加1)。和SYN一样,一个FIN将占用一个序号。
接着这个服务器程序就关闭它的连接,并发送一个FIN,客户必须发回一个确认,并将确认序号设置为收到序号加1。

主动关闭&被动关闭

首先进行关闭的一方(即发送第一个 FIN)将执行主动关闭,而另一方(收到这个 FIN)执行被动关闭。通常一方完成主动关闭而另一方完成被动关闭

同时关闭

TCP协议支持连接双方都执行主动关闭,也就是同时关闭。

image.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值