分享

TCP状态转换图文解说

 流楚丶格念 2022-01-14

文章目录

一、TCP状态转换图

说明

在这里插入图片描述

状态转换图

在这里插入图片描述

  • TCP初始化时从CLOSED状态启动,通常根据是执行主动打开操作(客户端请求)还是被动打开操作(服务器接收请求),TCP将分别转换到SYN_SENT或LISTEN状态。正常情况下处于这两个状态下的两者由此建立了连接,这就是三次握手过程。
  • 左下方的FIN_WAIT_1、FIN_WAIT_2以及TIME_WAIT是“主动关闭”过程的状态转换,而CLOWSE_WAIT和LAST_ACK则是“被动关闭”过程涉及的状态转换。
  • 从LISTEN到SYN_SENT的状态转换只有在WYN_RCVD状态是由LISTEN状态而非WYN_SENT状态转换而来的情况下才会发生。这意味着,如果我们执行一个被动打开操作(进入LISTEN状态),接收一个SYN,发送一个带有ACK确认的SYN(进入SYN_RCVD状态),然后收到一个重置消息而非ACK,套接字就会返回到LISTEN状态,等待另一个连接请求的到来。

  • 结合TCP连接从建立到终止的过程,可以得到下图:

在这里插入图片描述
两张图一一对应,同志们可按照流程对照

二、名次解释

2MSL

a. 等待时长
b. 主动关闭连接的一方, 处于TIME_WAIT状态
c. 有的地方: 2分钟, 30s, 一般时候是30s(MSL)

半关闭

理解

  • A给B发送是FIN(A调用了close函数), 但是B没有给
    A发送FIN(B没有调用close)
  • A断开了与B的连接, B没有断开与A的连接

特点

  • A不能给B发送数据, A可以收B发送的数据
  • B可以给A发送数据

函数: int shutdown(int sockfd, int how);

  • sockfd: 要半关闭的一方对应的通信文件描述符
  • how:
    • SHUT_RD - 0 - 读
    • SHUT_WR - 1 - 写
    • SHUT_RDWR - 2 - 读写

补充:Linux命令:查看网络相关状态

命令:netstat

  • 参数:
    –a (all)显示所有选项,默认不显示LISTEN相关
    -p 显示建立相关链接的程序名
    -n 拒绝显示别名,能显示数字的全部转化成数字。
    -t (tcp)仅显示tcp相关选项
    -u (udp)仅显示udp相关选项
    -l 仅列出有在 Listen (监听) 的服务状态

补充:端口复用

端口复用最常用的用途是:

  • 防止服务器重启时之前绑定的端口还未释放
  • 程序突然退出而系统没有释放端口

设置方法:

int opt = 1; 
 SO_REUSEADDR, 
setsockopt(sockfd, SOL_SOCKET, 
 (const void *)&opt, sizeof(opt)); `

注意事项:

  • 绑定之前设置端口复用的属性

FIN_WAIT2

在FIN_WAIT2状态,TCP连接的主动关闭方已发送一个FIN报文段并得到另一端确认。除非出现半关闭的情况,否则主动关闭方将会等待另一端识别出自己已接收到一个文件末尾的通知并执行关闭连接操作。只有主动关闭方接收到另一端的FIN报文段,才会从FIN_WAIT2状态转移至TIME_WAIT状态。

TIME_WAIT

TIME_WAIT状态也称为2MSL等待状态。在该状态中,TCP套接字将会等待两倍于最大段生存期(Maximum Segment Lifetime,MSL)的时间。它代表任何报文段在被丢弃前在网络中允许存在的最长时间。虽然允许设置这个数值,但同时也受到网络层中IP数据报TTL字段的影响,因为TCP报文是以IP数据报的形式传输的。

当TCP连接主动关闭方接收到被动关闭方发送的FIN和最终的ACK后,连接的主动关闭方必须处于TIME_WAIT状态并持续2MSL时间。这样就能够让TCP连接的主动关闭方在它发送的ACK丢失的情况下重新发送最终的ACK。主动关闭方重新发送的最终ACK并不是因为被动关闭方重传了ACK(它们并不消耗序列号,被动关闭方也不会重传),而是因为被动关闭方重传了它的FIN。事实上,被动关闭方总是重传FIN直到它收到一个最终的ACK。

假设没有TIME_WAIT状态,如果被动关闭方没有收到主动关闭方回复的ACK,它就会重新发送FIN,但此时主动关闭方已经处于CLOSED状态,因此会响应一个RST报文段,让被动关闭方误认为发生了错误。因此TIME_WAIT状态存在的其中一个原因就是为实现TCP连接的可靠释放。

使用TIME_WAIT状态的另一个原因是为使旧的数据包在网络因过期而消失。假设TCP协议中不存在TIME_WAIT状态的限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port)。因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。由于一个连接仅由两对socket唯一标识,因此TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立的过程对其来说是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。

出于第2个原因的考虑,TCP协议规定在TIME_WAIT状态时,通信双方将连接(客户端IP地址、客户端端口号、服务器IP地址、服务器端口号)置于不可用状态。只有当2MSL等待结束时,或一条新连接使用的初始序列号超过了连接之前的实例所使用的最高序列号时[RFC1122],或者允许使用时间戳选项来区分之前连接实例的报文段以避免混淆时[RFC6191],这条连接才能重新使用。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多