TCP协议那些事儿

本篇用于积累TCP的原理知识,主要为摘抄内容,非原创。TCP是面向连接的、可靠的、有序的、无丢失无重复的数据传输协议,面向字节流。

TCP三次握手

在这里插入图片描述在这里插入图片描述
TCP三次握手的主要目的是同步序列号,只有同步序列号之后才能实现可靠传输,在TCP头部格式中有SYN位和32位序列号两个部分实现。

客户端/服务器端超时重传机制

在客户端发送SYN之后没有收到ACK+SYN,则会超时重传SYN包,每次超时是上次的两倍,重传次数由tcp_syn_retries参数控制。假设retries次数是5,则总耗时:1+2+4+8+16+32=63s,所以在网络稳定时为提高效率则可以适当调低次数,反之则调高次数。
在这里插入图片描述

服务器端半连接队列

在服务器端收到SYN后,服务器会变成SYN_RCV状态,维护一个队列来维护“未完成”的握手信息,一旦SYN_queue溢出,则无法建立新的连接。
半连接队列由长度不仅需要tcp_max_syn_backlog,还有backlog和somaxconn的值(控制accept队列大小)共同控制。

可以用netstat -s 查看丢弃连接的情况,输出值为累计值:
在这里插入图片描述

服务器端遭到SYN攻击

SYN攻击发生在此处,攻击的就是这个半连接队列。
解决办法:tcp_syn_cookies功能开启后可以在不使用半连接队列的情况下成功建立连接。工作原理为,服务器根据当前状态计算出一个哈希值,放在SYN+ACK中一同发出,当客户端返回ACK报文时,去除该值验证,如果合法则认为建立连接成功。

  • 服务器端全连接队列
    在服务器接收到ACK后建立连接成功,此时半连接队列移除,创建新连接添加到ACCEPT队列,这个时候需要accept函数将连接取出,否则accept_queue移除导致建立好的TCP连接被丢弃。accept队列的长度由somaxconn和backlog之间的最小值决定。somaxconn是内核参数,backlog是lisen中的第二个参数。

accept队列长度可以通过ss -ltn命令查看:
在这里插入图片描述

全连接队列的溢出,丢包与RST报文

溢出时丢包是队列溢出时默认行为,我们可以选择向客户端发送RST复位报文。tcp_abort_on_overflow可以打开此功能,在客户端异常时会看到connection reset by peer,但是默认情况下应该为0,有利于应对突发流量。因为有时候服务器上的进程只是短暂的繁忙。
在这里插入图片描述

绕过三次挥手

TCP fast open功能,第一次发起http+get请求的时候,需要三次握手流程,之后客户端再次向服务器建立连接时,可以绕过三次握手,减少一个RTT流程。可以通过设置tcp_fastopen内核参数来打开fast open功能。

TCP四次挥手

在这里插入图片描述四次挥手只有FIN和ACK两种信号,只有主动发起关闭的一方会有time_wait。
通常关闭连接的方式有两种:RST暴力关闭方式和FIN四次挥手流程。关闭连接的函数有两种:关闭两头的close函数和只关闭一方的shutdown函数。

客户端的超时重传/FIN_WAIT1状态

主动放发送FIN报文后收不到ACK就会处于FIN_WAIT1的状态,有超时重传机制,一般如果FIN_WAIT1状态连接很多,我们需要考虑降低tcp_orphan_retries的值,当重传次数超过时就会直接关闭。

客户端的孤儿连接/FIN_WAIT1状态

当遇到恶意攻击无法发出FIN报文时,一直处于FIN_WAIT1状态。调用了close函数的一方的叫做孤儿连接,为了防止孤儿连接过多资源占用,则提供tcp_max_orphans控制,如果超过则新增的孤儿连接不走四次挥手直接关闭。

客户端的FIN_WAIT2状态

主动放收到ACK报文后处于FIN_WAIT2状态,当FIN_WAIT2状态连接很多时,我们就需要降低次数,当重传次数超过它时,连接就会直接关闭掉。close函数关闭的孤儿连接,这个状态无法持续太久,因为无法发送和接收数据,而调用shutdown函数关闭的连接可以一直处于FIN_WAIT2状态,tcp_fin_timeout控制了这个状态下的持续时长,默认时常是60s,它与后面的TIME_WAIT状态持续时间时相同的。

客户端的TIME_WAIT时间

原因一:防止旧连接的发送延迟的包
原因二:保证连接正确关闭,允许报文至少丢失一次,则重发FIN会在第二个MSL内到达。
虽然time_wait的存在是必要的,但是它毕竟会消耗资源,所以可以调整时间控制time_wait上限个数(tcp_max_tw_buckets)。如果time_wait参数超过该参数时,新关闭的连接不再经历time_wait而直接关闭。

客户端的复用time_wait状态连接+时间戳

打开tcp_tw_reuse参数,但是该参数只用于客户端,在调用connect的时候才起作用,对于客户端时没有用的。同时要打开时间戳tcp_timestamps,会因为时间戳过期而被丢弃,也可以防止重复的数据包绕回。

服务器端的被动策略

被动关闭的连接应对非常简单,在收到FIN报文时,内核会自动回复ACK,处于close_wait状态等待应用进程调用close函数关闭连接。内核自己没有权利去关闭,如果用netstat命令发现有大量close_wait状态,则说明应用程序有问题,要去排查。

TCP数据发送

TCP发送报文之后不会立刻删除,会用于重传。所以如果TCP是每发送一个数据都要进行一次确认应答,效率很低,所以进行并行批量发送报文。滑动窗口是用来控制发送方发送数据量的。
内核收到报文,用缓存区存放,接收窗口变小;用read函数后数据被读入用户空间,内核缓冲区被清空,窗口变大。
TCP头部的窗口大小为2个字节,即64KB。可以通过tcp_window_scaling去扩大窗口,当然也不会无限增大,因为还收网络限制。

设置缓冲区大小

调节发送缓冲区范围:tcp_wmem,自动调节功能自动开启。
调节接收缓冲区范围:tcp_rmem,根据tcp_moderate_rcvbuf来开启自动调节功能。
调节内存范围:tcp_mem

TCP提高性能方式

在这里插入图片描述

巨人的肩膀:
[1] 小林coding:https://mp.weixin.qq.com/s/0VtugnDC5V30EZrctpGwKA

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值