TCP 被定义为面向连接的可靠协议,这里主要讲一下TCP的面向连接特性!
TCP面向连接
TCP会话起于三次握手、终于四次挥手,整个过程是带连接管理的,只有连接正常的情况下TCP才能正常的传输数据。
TCP三次握手
tcp三次握手过程
为什么握手要三次?
主要在于为什么需要最后一次ACK,如果是两次就握手成功,Host1发第一个SYN包在网络中丢失,然后重发SYN包,SYN包到了Host2,Host2回复SYN+ACK就建立连接了,然后数据传输,连接关闭,之后第一个SYN包又来到了Host2,这个时候Host2回复SYN+ACK进入已连接状态,Host1其实已经释放了连接,这时Host2的连接资源将一直无法释放。
tcp三次握手抓包
tcp三次握手linux内核主要系统参数
tcp端点 | tcp内核参数 | 参数解释 |
client | net.ipv4.tcp_syn_retries | SYN重试次数 |
server | net.ipv4.tcp_max_syn_backlog、net.core.somaxconn | SYN半连接队列大小 |
server | net.ipv4.tcp_synack_retries | SYN+ACK重试次数 |
client&server | net.ipv4.tcp_fastopen | fastopen是否启用 |
TCP四次挥手
tcp四次挥手过程
为什么挥手要四次?
挥手为什么要四次比握手多一次,主要是Host1发送FIN到Host2后,Host2可能还有数据需要传输给Host1,这个时候会先回复ACK,然后Host2等待传输完所有数据再发送FIN给Host1,Host1最后回复ACK给Host2从而完成挥手过程,资源可以释放(在Host2没有数据传输给Host1的情况下,ACK和FIN会同一个包传输给Host1,就是图中的合并场景,这个时候看起来就是三次挥手)。
tcp四次挥手抓包
tcp四次挥手linux内核主要系统参数
tcp端点 | tcp内核参数 | 参数解释 |
主动方 | net.ipv4.tcp_orphan_retries | FIN包重试次数 |
主动方 | net.ipv4.tcp_fin_timeout | FIN_WAIT_2超时时间 |
被动方 | net.ipv4.tcp_max_orphans | 孤儿连接上限数 |
被动方 | net.ipv4.tcp_max_tw_buckets | TIME_WAIT上限数 |
被动方(client) | net.ipv4.tcp_tw_reuse、net.ipv4.tcp_timestamps | 复用TIME_WAIT的连接 |
tcp连接管理
tcp状态转移图
tcp实际运行连接问题
- tcp两端同时发起建立连接(call collision)
两端同时发起连接情况下,两端发完SYN进入SYN_SEND状态,然后几乎同时收到SYN回复SYN+ACK进入到SYN_RCVD状态,最后几乎同时收到SYN+ACK会进入ESTABLISHED状态,这个时候最终建立的是一条连接,并非两条连接(socket只有一个)
- tcp两端同时关闭连接
两端同时发FIN,然后会同时ACL后进入CLOSING->TIME_WAIT->CLOSED
- tcp断开被动方出现大量CLOSE_WAIT
通常是服务端,CLOSE_WAIT后应用层代码问题没有close socket,一直无法进入LAST_ACK,这种情况linux可以通过net.ipv4.tcp_keepalive_time内核参数设置超时,更重要的是修复代码bug(异常情况下注意close socket)
- tcp断开主动方出现大量FIN_WAIT_2
主动方在FIN_WAIT_2半连接状态时收不到被动方发的FIN就无法进入TIME_WAIT,linux可通过net.ipv4.tcp_fin_timeout内核参数(其实就是msl)设置fin超时
- tcp断开主动方出现大量TIME_WAIT
主动方进入TIME_WAIT状态需要等待2msl(2个msl是保证收到重传ACK的时间)时间进入CLOSED,等待2msl时间主要为了被动方能收到最后一个ACK应答,如果最后一个ACK应答丢失,被动方能重发FIN,然后重传最后一个ACK,由于tcp都需要close以后端口资源才能回收利用,出现大量的TIME_WAIT占用太多端口资源可能造成资源枯竭,linux上可适当修改net.ipv4.tcp_fin_timeout来修改msl进行优化,也可以通过net.ipv4.tcp_max_tw_buckets参数(TIME_WAIT上限)来进行一定的限制
- 被动方LAST_ACK收不到最后ACK
最后的ACK丢失,若主动方在TIME_WAIT状态,被动方重发FIN来触发最后ACK重传,从而进入CLOSED,若主动方已经进入CLOSED,被动方重发FIN来触发回复RST,从而进入CLOSED,最终都能顺利进入CLOSED
tcp连接linux内核主要参数
# tcp客户端SYN连接请求重试次数
net.ipv4.tcp_syn_retries=6
# tcp服务端SYN+ACK回复重试次数
net.ipv4.tcp_synack_retries=5
# tcp服务端SYN Cookies,出现SYN等待队列溢出时,启用cookies来处理,可防范SYN Flood攻击,默认为1,表示开启,0为关闭,2为无条件生成
net.ipv4.tcp_syncookies = 1
# tcp服务端SYN队列的长度,默认为1024,加大队列长度可以accept的网络连接数,net.core.somaxconn参数也会影响队列大小,两者需要同时配置
net.ipv4.tcp_max_syn_backlog = 1024
# 0x1: (client) 默认值,开启客户端TFO, 但是必须使用sendto()或sendmsg()调用,不能使用connect()
# 0x2: (server) 开启服务端TFO支持
# 0x4: (client) 发送syn+数据,而不管cookie的有效性,不带fast open coookie选项
# 0x200: (server) 接受TFO, 而不管cookie选项
# 0x400: (server) 所有listener都支持,不用显式设置TCP_FASTOPEN socket选项
net.ipv4.tcp_fastopen = 1
# tcp keepalive启用后,keepalive消息发送间隔,缺省是2小时
net.ipv4.tcp_keepalive_time=7200
# tcp端口主动方FIN包重试次数
net.ipv4.tcp_orphan_retries=0
# tcp TIME_WAIT最大上限,超过后会清除
net.ipv4.tcp_max_tw_buckets = 5000
# tcp主动方保持在FIN-WAIT-2状态的时间,也同样是tcp msl时间
net.ipv4.tcp_fin_timeout=60
# tcp是否重用TIME_WAIT的socket,默认为0,表示关闭,可配置为1重用TIME_WAIT连接
net.ipv4.tcp_tw_reuse = 0
# 网络设备接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
net.core.netdev_max_backlog=5000
本文暂时没有评论,来添加一个吧(●'◡'●)