- 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
a) 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
b) 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
c) 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据。 - 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
a) 客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送
b) 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1和SYN一样,一个FIN将占用一个序号。
c) 服务器B关闭与客户端A的连接,发送一个FIN给客户端A
d) 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1
SYN Flood的攻击:
在进行三次握手时,攻击软件向被攻击的服务器发送SYN连接请求(握手的第一步),但是这个地址是伪造的,如攻击软件随机伪造了51.133.163.104、65.158.99.152等等地址。服务器在收到连接请求时将标志位ACK和SYN置1发送给客户端(握手的第二步),但是这些客户端的IP地址都是伪造的,服务器根本找不到客户机,也就是说握手的第三步不可能完成。
这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒-2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源—-数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。此时从正常客户的角度看来,服务器失去响应,这种情况我们称做:服务器端受到了SYN Flood攻击(SYN洪水攻击)
保活机制
TCP保活可能带来的问题
1, 中间设备因大量保活连接,导致其连接表满
网关设备由于保活问题,导致其连接表满,无法新建连接(XX局网闸故障案例)或性能下降严重
2, 正常连接被释放
当连接一端在发送保活探测报文时,中间网络正好由于各种异常(如链路中断、中间设备重启等)而无法将该保活探测报文正确转发至对端时,可能会导致探测的一方释放本来正常的连接,但是这种可能情况发生的概率较小,另外,一般也可以增加保活探测报文发生的次数来减小这种情况发生的概率和影响。
TIME-WAIT
为什么TIME_WAIT状态还需要等2MSL(默认情况下一个MSL=30s)后才能返回到CLOSED状态?
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。
FIN-WAIT1 和FIN-WAIT2 的区别
FIN-WAIT1处于主动关闭连接一方,被动关闭一方会将剩余数据进行传输,然后再ack变为可关闭。
FIN-WAIT1处于主动关闭连接一方,接受到被动关闭一方ack会进入这个状态,直到被动接受到被动关闭的报文。
TCP/IP四种计时器
a) 重传计时器:控制超时重传,若在计时器超时之前收到对报文段的确认,则撤销计时器;若在收到对特定报文段的确认之前计时器超时,则重传该报文,并把计时器复位。
b) 坚持计时器:当滑动窗口的大小为0的时候,建立一个坚持计时器,不断查询客户端的滑动窗口大小,直到滑动窗口的大小不为0,销毁计时器,发送数据包。
c) 保活计时器:每当服务器收到客户的信息,就将keeplive timer复位,超时通常设置2小时,若服务器超过2小时还没有收到来自客户的信息,就发送探测报文段,若发送了10个探测报文段(没75秒发送一个)还没收到响应,则终止连接。
d) 时间等待计时器:在连接终止期使用,当TCP关闭连接时,并不认为这个连接就真正关闭了,在时间等待期间,连接还处于一种中间过度状态。这样就可以时重复的fin报文段在到达终点后被丢弃,这个计时器的值通常设置为一格报文段寿命期望值的两倍
Tcp/Ip协议的RST包:
在TCP协议中RST表示复位,用来异常的关闭连接,在TCP的设计中它是不可或缺的。
发送RST包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓存区的包发送RST包。而接收端收到RST包后,也不必发送ACK包来确认。
以下情况可能出现发送RST包:
1. 端口未打开,可能导致回应RST包,不同的操作系统应对策略不同
2. 请求超时,发送RST拒绝下一步的数据传输
3. 提前关闭,应用程序如果接收不到Tcp/Ip的数据,发送RST关闭连接
4. 如果某个socket已经关闭,但依然收到数据也会产生RST
四次挥手途中得不到ack确认关闭连接,会进行超时重传,然后启动计数器对重传次数进行统计,如果超过了一定次数,抛弃缓冲区的包直接发送RST关闭连接。
四次挥手合并
如果需要支持半关闭机制,则需要四次挥手,否则可以使用三次挥手,即B同时发送(FIN+ACK),TCP的延迟确认机制:延迟确认就是Server对Client的FIN报文的确认延迟到和Server的FIN一起发,实际上就是三次挥手。
TCP延迟策略
tcp发送ack有两种方式:quick ack 和 delayed ack
quick ack:收到数据包后,立即发送ACK给对端。
delayed ack:收到数据包后,不会立即发送ACK,而是启动延时确认定时器,在此期间:
1. 本端有数据包要发送给对端。就在发送数据包的时候捎带上此ACK。
2. 本端没有数据包要发送,定时器超时后发送ACK给对端。
参考链接
延迟ACK的目的也是为了减少网络中传输大量的小报文数,但该报文数是针对ACK报文的。
一个来自发送端的报文到达接收端,TCP会延迟ACK的发送,希望应用程序会对刚刚收到的数据进行应答,这样就可以用新数据将ACK捎带过。
满足下列条件之一,需要立即发送ack,否则进入延迟确认模式:
- 收到大于mss的包且有能力接收数据
- 满足快速确认模式
- 有乱序的数据,需要对端重传
TCP 长连接如何分包:
- 定长数据包(http请求包含content-length)
- 包含特定分隔符的变长数据包
- 先传长度再传包体的变长数据包
- 分片传输(其实就是分时传输,用来解决并行传输问题)