tcp状态机详解

      windos 进程管理
      TCP包头
      TCP三次握手
      TCP四次断开
      FSM:Finite State Machine

1、win cmd查看指定进程运行进程号

C:\Users\Administrator>tasklist |findstr vmware
vmware-authd.exe              4428 Services                   0      8,724 K
vmware-usbarbitrator64.ex     5044 Services                   0      6,980 K
vmware-hostd.exe              5332 Services                   0     25,536 K
vmware.exe                    4228 Console                    1     57,132 K
vmware-unity-helper.exe       9968 Console                    1     11,280 K
vmware-vmx.exe                5740 Console                    1  1,023,584 K
vmware-vmx.exe                9148 Console                    1  1,044,284 K

cmd中查看进程监听端口

C:\Users\Administrator>netstat -no | findstr 4228
  TCP    127.0.0.1:50732        127.0.0.1:443          ESTABLISHED     4228
  TCP    127.0.0.1:50764        127.0.0.1:50765        ESTABLISHED     4228
  TCP    127.0.0.1:50765        127.0.0.1:50764        ESTABLISHED     4228
  TCP    127.0.0.1:51036        127.0.0.1:51037        ESTABLISHED     4228
  TCP    127.0.0.1:51037        127.0.0.1:51036        ESTABLISHED     4228
  TCP    [::1]:50733            [::1]:50734            ESTABLISHED     4228
  TCP    [::1]:50734            [::1]:50733            ESTABLISHED     4228

 

2、TCP包头

tcp状态机详解_第1张图片

源端口(src 16位): 数据发送端端口占据16位,根据计算机端口位数可推算出计算机端口个数为2^16=0-65535

目标端口(dst 16位): 数据到达目的端的端口占据16位

序列号(seq 32位): 报文段发送数据第一个字节的编号,传输的每一个自建都是按照顺序编号,由32位即2^32=0-4294967295表示序列号,如果编号全部用完在,再从第0个开始轮换

确认号(ack 32位): 期望收到数据的开始序列号,即已经收到的数据字段长度加1

序列号和确认号关联
      通过序列号(seq)和确认号(ack)反复确认,从而保证数据完整性;但是过于麻烦,效率过低;
序列号发送请求,确认号(包的编号)确认接收数据;
  C端:Ack1表示之前的S端第一个包0包收到的了,固确认编号为1;
  C端:请求10希望S端回复11;确认接收后,希望发送下一个数据,就回复11.

数据偏移(4位): 20个字节是固定首部不变的,有一部分是可变的加了可选项后,即说明该头部信息有多大,该端单位时32位(即4个字节),4位二进制最大表示15,所以数据偏移也就是TCP首部最大60字节

保留(3位): 空余没用的选项

标志符(6位)

  两种状态 0|1
  URG: 紧急指针位 0表示无效 1有效

  *ACK: 确认报文段 1 确认前面的确认号字段有效

  PSH: 1 立即把数据交给上层应用,不缓存
  0如果应用程序一直不读取,则停留在TCP接受缓冲区中

  RST: 0 数据传输正常; 1 传输出现错误,重新建立连接 即复位报文段

  *SYN: 创建连接和同步
  SYN=1 ACK=0 请求 --> SYN=1 ACK=1 同步

  *FIN 结束 发送发没有数据传输了,就释放连接

窗口(16位): 定义了数据包的传递大小,决定了通信效率,从确认号开始,报文发送方可接收的字节数

  固定窗口
  Window Size = 3 or Window Size = 1
  窗口固定包的速率不符合网络实际情况,容易丢包

  滑动窗口:根据测试实际网络发送包

校验和(Checksum,16位): 对整个的TCP报文段,包括TCP头部和TCP数据,这是一个强制性的字段,以16位字节进行计算所得,提供额外的可靠性

紧急指针(16位): 紧急数据的最后一个字节的序号。

选项字段(40字节):每个选项的开始是1字节的kind字段,说明选项的类型。(2^4-1)*4-20=40字节
  0:选项表结束(1字节)
  1:无操作(1字节)用于选项字段之间的字边界对齐。
  2:最大报文段长度(4字节,Maximum Segment Size,MSS)通常在创建连接而设置SYN标志的数据包中指明这个选项,指明本端所能接收的最大长度的报文段。通常将MSS设置为(MTU-40)字节,携带TCP报文段的IP数据报的长度就不会超过MTU(MTU最大长度为1518字节,最短为64字节),从而避免本机发生IP分片。只能出现在同步报文段中,否则将被忽略。
  3:窗口扩大(4字节,wscale),取值0-14。用来把TCP的窗口的值左移的位数,使窗口值乘倍。只能出现在同步报文段中,否则将被忽略。这是因为现在的TCP接收数据缓冲区(接收窗口)的长度通常大于2^16=65535字节。
  4:sackOK—发送端支持并同意使用SACK选项。
  5:SACK实际工作的选项。
  8:时间戳(10字节,TCP Timestamps Option,TSopt)
发送端的时间戳(Timestamp Value field,TSval,4字节)
时间戳回显应答(Timestamp Echo Reply field,TSecr,4字节)可以用来计算RTT(往返时间),发送方发送TCP报文时,把当前的时间值放入时间戳字段,接收方收到后发送确认报文时,把这个时间戳字段的值复制到确认报文中,当发送方收到确认报文后即可计算出RTT

3、TCP三次握手

tcp状态机详解_第2张图片

CLOSED关闭状态, LISTEN收听状态,SYN-SENT同步已发送,SYN-RCVD同步已收到,ESTAB-LISHED建立连接

为什么要三次握手
    通信双方的通信结果双方都能最终确认故要三次握手,是通信建立最低保证,多了则浪费,没有意义;客户端在发送了SYN数据报后可能碰到网络拥塞,过了超时重传的等待时间后客户端没有收到服务端的ACK,所以它又发送了第二次SYN报文段,此时服务端发送过来了前一个SYN应答报文段;但是可能过了一会,刚刚处于拥塞环境的SYN报文段又到达了服务端,这时服务端会认为客户端想和自己建立第二次连接,于是又向客户端发送了SYN应答报文段,而此时客户端可能已经完成了数据传送并释放了和服务端的连接,它的状态会变为CLOSED,从而导致永远无法收到服务端发来的SYN报文段,从而使服务端一直再等待客户端发来数据。

三次握手通信过程

客户端主动发起请求SYN=1,再发送一个随机序列号seq=x,此时server端被动打开端口收听客户端请求

服务端收到请求后,回复一个确认号,ack=x+1;并确认前面的确认号有效ACK=1,此时在发送响应到客户端,请求内容seq=y, SYN=1

客户端收到回复后,转入同步已发送状态;确认服务端的信息后,回复确认号ack=y+1,并确认ack有效,即ACK=1,并把请求同步给server,seq=x+1

服务端收到后随即转入同步收到状态

c/s都进入ESTAB-LISHED状态,数据开始传送

sync半连接 (sync queue)
    如果服务器端接到了客户端发的SYN后回了SYN-ACK后客户端掉线了,服务器端没有收到客户端回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。于是,服务器端如果在一定时间内没有收到的TCP会重发SYN-ACK。

两次握手最大队列长度限制 未完成连接队列大小,建议调整大小为1024以上
Centos7默认为128
[root@centos7 /proc/1]#/proc/sys/net/ipv4/tcp_max_syn_backlog

超出syn最大队列长度采取的措施(如果监听服务太慢并且无法跟上并接受它们,请启用重置连接。)
默认为0禁用不采取措施
[root@centos7 /proc/1]#cat /proc/sys/net/ipv4/tcp_abort_on_overflow

重试次数 centos7默认5次,重试的间隔时间从1s开始每次都翻倍,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s才知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才会断开这个连接。
[root@centos7 /proc/1]#cat /proc/sys/net/ipv4/tcp_synack_retries

accept全连接队列 (accept queue)
如果建立连接后,没有回应,不然会造成队列拥堵
完成连接队列大小,建议调整大小为1024以上
#cat /proc/sys/net/core/somaxconn centos7 centos6都是128

TCP超时重传: 异常网络下,保障数据的重传传输次数,发送方使用一个保守估计的时间作为收到数据包的确认的超时上限。如果超过这个上限仍未收到确认包,发送方将重传这个数据包。每当发送方收到确认包后,会重置这个重传定时器。
#/proc/sys/net/ipv4/tcp_retries1 #最小重新传数,默认3
#/proc/sys/net/ipv4/tcp_retires2 #最大重新传数后放弃传输默认15 (一般对应13min-30min)

拥塞控制: 网络中如果某个资源超过了源可承受的负载,造成网络的衰退,tcp为了保持数据流的公平性故而做了拥塞控制(TRFC 5681文档)
控制机制: 慢启动(slow start) 拥塞避免(congestion avoidance) 快速重传(fast retransmit) 快速恢复(fast recovery)
Linux实现的该控制机制用到的算法有reno、vegas、cubic算法等
#/proc/sys/net/ipv4/tcp_congestion_control #查看默认拥塞控制算法

扩展:交换机机stp协议
      因为交换机闭环连接后容易造成网络风暴,为了避免。所以有了stp生成树协议;由交换机管控,在逻辑上断开某一端口,避免风暴产生,如有线路断开,再自动启用,避免网络故障。

4、TCP四次断开

tcp状态机详解_第3张图片

ESTAB-LISHED建立连接 CLOSE-WAIT关闭等待,FIN-WAIT-1终止等待1,FIN-WAIT-2终止等待2,TIME-WAIT时间等待,LAST-ACK最后确认,CLOSED关闭状态

C/S端都可以主动分手,看实际需求

四次断开过程

当C端提出断开连接请求后立即进入FIN-WAIT-1状态,发送FIN=1,seq=u 发送结束请求
S端收到后不会立即断开,要向C端确认断开信息,先确认断开请求已收到,CLOSE-WAIT
C端收到后立即进入FIN-WAIT-2状态
    注: S端确认收到对方的断开请求后,不会立即断开,因为会有s端某些需要发给C端的数据可能没传输结束。最终确认后再同意断开请求
S端同意断开请求,回复断开请求指令seq=1,并确认前面的确认号正确ACK=1
C端随即进入TIME-WAIT状态,等待2MSL;再确认断开请求给S
S端进入LAST-ACK状态后
C/S端关闭数数据连接

MSL 最大的数据段生存时长
MSL国际定义的2min centos30S 不同系统不一样
给予足够的时长,等待2MSL避免数据丢失

孤儿连接
    由于客服端长时间处于FIN-WAIT-2状态,等不到服务端的中端请求,就到达不了TIME_WAIT状态,会处于半关闭假死状态。由此客户端强行关闭后,连接由内核接管,即为孤儿连接
#/proc/sys/net/ipv4/tcp_max_orphans #内核管理的最大孤儿连接数
#/proc/sys/net/ipv4/tcp_fin_timeout #最大孤儿连接生存时长

5、FSM:Finite State Machine

tcp状态机详解_第4张图片

客户端先发送一个FIN给服务端,自己进入了FIN_WAIT_1状态,这时等待接收服务端的报文,该报文会有三种可能:
    1)、只有服务端的ACK
    2)、只有服务端的FIN
    3)、基于服务端的ACK,又有FIN

1、只收到服务器的ACK,客户端会进入FIN_WAIT_2状态,后续当收到服务端的FIN时,回应发送一个ACK,会进入到TIME_WAIT状态,这个状态会持续2MSL(TCP报文段在网络中的最大生存时间, RFC 1122标准的建议值是2min).客户端等待2MSL,是为了当最后一个ACK丢失时,可以再发送一次。因为服务端在等待超时后会再发送一个FIN给客户端,进而客户端知道ACK已丢失

2、只有服务端的FIN时,回应一个ACK给服务端,
客户端进入CLOSING状态,然后接收到服务端的ACK时,进入TIME_WAIT状态

3、同时收到服务端的ACK和FIN,
客户端直接进入TIME_WAIT状态

十一种有限状态

CLOSED 没有任何连接状态
LISTEN 侦听状态,等待来自远方TCP端口的连接请求
SYN-SENT 在发送连接请求后,等待对方确认
SYN-RECEIVED 在收到和发送一个连接请求后,等待对方确认
ESTABLISHED 代表传输连接建立,双方进入数据传送状态
FIN-WAIT-1 主动关闭,主机已发送关闭连接请求,等待对方确认
FIN-WAIT-2 主动关闭,主机已收到对方关闭传输连接确认,等待对方发送关闭传输连接请求
TIME-WAIT 完成双向传输连接关闭,等待所有分组消失
CLOSE-WAIT 被动关闭,收到对方发来的关闭连接请求,并已确认
LAST-ACK 被动关闭,等待最后一个关闭传输连接确认,并等待所有分组消失
CLOSING 双方同时尝试关闭传输连接,等待对方确认

客户端的典型状态转移
    客户端通过connect系统调用主动与服务器建立连接connect系统调用首先给服务器发送一个同步报文段,使连接转移到SYN_SENT状态
此后connect系统调用可能因为如下两个原因失败返回:

1、如果connect连接的目标端口不存在(未被任何进程监听),或者该端口仍被处于TIME_WAIT状态的连接所占用(见后文),则服务器将给客户端发送一个复位报文段,connect调用失败。

2、如果目标端口存在,但connect在超时时间内未收到服务器的确认报文段,则connect调用失败。

connect调用失败将使连接立即返回到初始的CLOSED状态。如果客户端成功收到服务器的同步报文段和确认,则connect调用成功返回,连接转移至ESTABLISHED状态

#man 7 tcp #查看更多tcp参数

你可能感兴趣的:(Network)