Linux网络总结三-TCP的可靠机制

TCP协议是一款基于连接的传输层协议,它最大的特点就是提供面向连接且提供可靠传输。这部分我们重点探究TCP的可靠性传输。
一 超时重连机制
我们知道在TCP建立连接的过程中,很多时候TCP连接并非是一次就可以建立完成的。有时候服务器由于网络繁忙无法对客户端的请求做出及时响应,那么此时客户端应该如何处理呢?我们进行如下实验:设置两台主机分别为:slave(192.168.188.130)与master(192.168.188.144)。我们在master执行如下操作:
sudo iptables –F
sudo iptables -I INPUT -p tcp --syn -i eth0 -j DROP
这一操作的目的是丢弃所有接收到的连接请求,即客户端无法收到服务端的确认报文段。
在slave执行如下操作:
sudo tcpdump -n -i eth0 port 23    //仅抓取23号端口的数据包
telnet 192.168.188.144                 //执行连接master操作
观察到如下信息:
 
我们观察到客户端共发起了6次请求,其中5次为重连请求,且依次时间间隔为1,2,4,8,16。这一点我们可以观察/proc/sys/net/ipv4/tcp_syn_retries观察到。文件值为5,意味着总共5次超时重连。
二 TIME-WAIT机制
1 TIME-WAIT的意义
在TCP连接四次挥手的过程中,主动关闭的一方会出现一个时间较长的状态TIME-WAIT。之所以会出现TIME-WAIT状态,主要是从TCP连接的可靠性出发的。其主要原因有两个:
第一:防止前一个连接上延迟的数据包或者丢失重传的数据包,被后面复用的连接错误的接收。端口再次被新的连接使用后,前一个连接发送的数据会被新的接收端错误接收。
第二,确保连接方能在时间范围内,关闭自己的连接。如果主动关闭一方没有TIME-WAIT,直接进入CLOSED状态,则被动关闭一方会因为收不到最后的ACK确认报文段永远处于LAST_ACK状态。
2 TIME-WAIT出现的原因
大家知道,由于socket是全双工的工作模式,一个socket的关闭,是需要四次握手来完成的。
主动关闭连接的一方,调用close();协议层发送FIN包
被动关闭的一方收到FIN包后,协议层回复ACK;然后被动关闭的一方,进入CLOSE_WAIT状态,主动关闭的一方等待对方关闭,则进入FIN_WAIT_2状态;此时,主动关闭的一方 等待 被动关闭一方的应用程序,调用close操作
被动关闭的一方在完成所有数据发送后,调用close()操作;此时,协议层发送FIN包给主动关闭的一方,等待对方的ACK,被动关闭的一方进入LAST_ACK状态;
主动关闭的一方收到FIN包,协议层回复ACK;此时,主动关闭连接的一方,进入TIME_WAIT状态;而被动关闭的一方,进入CLOSED状态
等待2MSL时间,主动关闭的一方,结束TIME_WAIT,进入CLOSED状态
被动关闭连接的一方,有一个中间状态,即CLOSE_WAIT,因为协议层在等待上层的应用程序,主动调用close操作后才主动关闭这条连接。
在一个连接没有进入CLOSED状态之前,这个连接是不能被重用的!
3 TIME_WAIT的处理办法
我们可以使用如下命令:ss -tan state time-wait | wc –l 观察系统中有多少处于TIME_WAIT状态的连接,因为TIME_WAIT导致连接无法进入CLOSED状态,进而导致端口在2MSL时间内无法被重用。
在内核中,TIME-WAIT状态的socket,对于三种不同的作用,有三个不同的结构。
第一个是“TCP established hash table”连接存储哈希表,用于有新的数据到来的时候,从这个hash table里快速找到这条连接。
我们可以通过如下命令观察:dmesg |grep -i "TCP established hash table "
第二个是一组叫做“death row”的链表,是用来终止TIME_WAIT状态的连接(socket)的。
第三个是hash table用来保存所有的bound ports,即存放调用后bind函数的port即其相关参数。
我们可以通过如下命令观察:dmesg |grep -i "TCP established hash table "
上述是与TIME-WAIT相关的三种队列结构。下面我们来消除TIME-WAIT影响的方法。
第一:禁用socket延迟关闭
通常情况当close被调用时,SOCKET需要延迟关闭(lingering),在内核buffers中的残留数据将会发送到远程地址,同时,socket会切换到TIME-WAIT状态。如果禁用此选项,则调用close之后,底层也会关闭,不会将Buffers中残留数据未发送的数据继续发送。
1.close函数后,并不会在发送FIN分节,取而代之的是发送RST分节,而在buffers任何残留数据都会被丢弃。在这种做法中,不会再有TIME-WAIT状态的SOCKET出现。
2.禁用net.ipv4.tcp_tw_reuse
3.禁用net.ipv4.tcp_tw_recycle
执行操作 sudo echo 1 >/proc/sys/net/ipv4/ tcp_tw_reuse
sudo echo 1 >/proc/sys/net/ipv4/ tcp_tw_recycle
将内核参数设置为1
tw_reuse只对客户端起作用,开启后客户端在1s内回收
tw_recycle 对客户端和服务器同时起作用,开启后在3.5*RTO 内回收,RTO 200ms~ 120s 具体时间视网络状况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值