TCP基础知识与Linux内核参数调优
一、概念¶
- 处理通信差错的方法: 使用差错校正码 重试重新发送,即自动重复请求(AutoARQ)
- ACK(acknowledgment,确认号):该确认号的发送方期待接收的下一个序列号,即最后被成功接收的数据字节的序列号+1
- seq(sequence number,序列号):标识了TCP发送端到TCP接收端的数据流的一个字节,该字节代表者该序列号报文段的数据中的第一个字节
- TCP:面向连接的(使用TCP的两个应用必须在他们交换数据之前,通过相互联系来建立一个TCP连接)、可靠的字节流服务。
- TCP连接是双向和对称的,数据可以在两个方向上平等的流动
- socket(套接字):一个IP地址和一个端口的组合
- 连接标识:4元组(客户端IP、客户端端口、服务端IP、服务端端口)
二、TCP连接的建立与终止¶
- TCP连接的构成:客户端IP、客户端端口、服务端IP、服务端端口
- TCP连接的3个阶段:启动、数据传输、退出(关闭)
- ISN(Initail Sequence Number,初始序列号):在发送用于建立连接的SYN之前,通信双方会选择一个初始序列号,序列号会随着时间而改变,因此每一个连接拥有不同的初始序列号,[RFC0793]指出初始序列号是一个32位的计数器,该计数器的值每4毫秒+1。Linux是采用基于时钟的方案,并且针对每一个连接为时钟设置随机的偏移量,随机偏移量是在连接标识的基础上利用加密散列函数得到的,散列函数的输入每隔5分钟就会更改一次。生产的序列号随着时间的增加而增加。
1. 三次握手¶
- 客户端发送一个SYN报文段,并指明自己想要连接的端口号和客户端初始序列号(ISN(c))
- 服务器也发送自己的SYN报文段作为响应,并包含了它的初始序列号(ISN(s)),此外,为了确认客户端的SYN,服务端将其包含的ISN(c)数值+1后作为返回的ACK数值
- 为了确认服务器的SYN,客户端将ISN(s)的数值+1后作为返回的ACK数值
2. 数据传输¶
交互数据流-以ssh为例
3.四次挥手¶
- 连接的主动关闭者发送一个FIN段指明接收者希望看到的自己当前的序列号(K),FIN还包含了一个ACK段用于确认对方最后一次发来的数据(L)
- 连接的被动关闭者将K的数值+1,最为响应的ACK,以表面它已经成功接收到主动关闭者发送的FIN。此时上层应用程序会被告知连接的另一端已经提出了关闭连接额请求,然后应用程序发起自己的关闭操作。接着被动关闭者将身份转变为主动关闭这,并发送自己的FIN,该报文段的序列号为L
- 为了完成连接的关闭,最后发送的报文还应包含一个ACK用于确认上一个FIN。如果FIN丢失的,那么发送方极爱那个重新传输直到接收一个ACK确认为止。
注意:一般情况下,负责发起关闭连接的通常是客户端,但是在一些服务器(Web服务器)在对请求做出响应之后也会发起一个关闭操作。
实例:
1 2 |
|
tcp抓包分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
问题: 为什么tcpdump
在四次挥手中只抓到三个步骤?
这里涉及到TCP的延时确认,在许多情况下,TCP并不对每个到来的数据包都返回ACK
,利用TCP的累计ACK
字段就能实现该功能,累积确认允许TCP延时一段时间发送ACK
,以便将ACK
和相同方向方向上需要传的数据结合发送。
在实验中使用curl命令时四次挥手过程只能抓到三个,使用浏览器的情况下,断开连接由服务器端发起,抓到四次挥手的全过程,如下所示:
1 2 3 4 5 6 7 8 |
|
flags含义: 标识|缩写|描述 :-:|:-:|:-- S|SYN|同步序号 F|FIN|发送方完成数据传送 R|RST|复位连接 P|PSH|尽可能快的将数据发送往接收进程 .||以上四个标识比特均置0
Linux对于连接的处理:¶
- 当一个请求到达(即SYN报文段),将会检查系统参数
net.ipv4.tcp_max_syn_backlog = 512
,如果处于SYN_RCVD
状态的连接数目超过这一阀值,进入的连接将会被拒绝。 - 处于监听状态下的节点都有一个固定长度的连接列队。如果连接已经被TCP接受(完成三次握手),但未被程序接受,应用程序会对这一列队做出限制,通常称为未完成连接(backlog)。Linux默认值为:
net.core.somaxconn = 128
几种连接状态(man netstat
):
状态 | 含义 |
---|---|
ESTABLISHED | The socket has an established connection. |
SYN_SENT | The socket is actively attempting to establish a connection. |
SYN_RECV | A connection request has been received from the network. |
FIN_WAIT1 | The socket is closed, and the connection is shutting down. |
FIN_WAIT2 | Connection is closed, and the socket is waiting for a shutdown from the remote end. |
TIME_WAIT | The socket is waiting after close to handle packets still in the network. |
CLOSE | The socket is not being used. |
CLOSE_WAIT | The remote end has shut down, waiting for the socket to close. |
LAST_ACK | The remote end has shut down, and the socket is closed. Waiting for acknowledgement. |
LISTEN | The socket is listening for incoming connections. Such sockets are not included in the output unless you specify the --listening (-l) or --all (-a) option. |
CLOSING | Both sockets are shut down but we still don't have all our data sent. |
更多解释 IBM 知识库tcp状态 维基百科 rfc793
TIME_WAIT(2MSL,Maximum Segment Lifetime):等待两倍与最大段存货其的时间,又称加倍等待。在Linux系统中net.ipv4.tcp_fin_timeout的数值记录了2MSL状态需要等待的超时时间(net.ipv4.tcp_fin_timeout = 60)。在发送最后一个ACK之前必须等待60秒,在此期间Server端会重传它的FIN(消耗一个序列号)之后收到最终的ACK。
TCP:攻击¶
SYN泛洪:TCP拒绝服务攻击。攻击者用一个或多个客户端伪造随机源IP地址,产生一系列TCP连接尝试(SYN报文段)并发送给服务器,服务器为每一条连接分配一定数量的连接资源,由于连接尚未完全建立,服务器为了维护大量的半打开连接会在耗尽自身内存后拒绝为后续合法的连接请求服务。 Linux服务器在接收到SYN后才采用下面的方法设置树池学列好
三、Linux内核参数优化¶
参数 | 描述 | 默认值 | 优化值 |
---|---|---|---|
net.ipv4.tcp_max_syn_backlog | TCP三次握手时,服务器没有收到客户端确认请求的连接数量(即SYN_RCVD状态的连接数量),对于内un较小的机器最小值是128,如果机器负载过高可以调高 | 512 | 优化值 |
net.ipv4.tcp_synack_retries | 为了打开对端的连接,内核需要发送一个SYN 并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。 | 5 | 3 |
net.ipv4.tcp_syncookies | 防止SYN Flood攻击 | 1 | 1 |
net.ipv4.tcp_keepalive_intvl | 探测消息未获得响应时,重发该消息的间隔时间(秒) | 75 | 30 |
net.ipv4.tcp_keepalive_probes | 在认定TCP连接失效之前,最多发送多少个keepalive探测消息 | 9 | 3 |
net.ipv4.tcp_keepalive_time | TCP发送keepalive探测消息的间隔时间(秒),用于确认TCP连接是否有效。 | 7200 | 1800 |
net.ipv4.tcp_tw_reuse | 表示是否允许将处于TIME-WAIT状态的socket(TIME-WAIT的端口)用于新的TCP连接 。 | 0 | 1 |
net.ipv4.tcp_tw_recycle | 更快地回收TIME-WAIT套接字,不建议改,kernel4.12以后被去除 | 0 | 0 |
net.ipv4.tcp_max_tw_buckets | 系统同时保留的最大时间等待套接字数。 如果超过此数量,则会立即销毁等待套接字并打印警告。这个值不建议调低,如果出现异常需要增大这个值。并扩大内存。 | 65536 | 65536 |
net.core.somaxconn | 处于监听状态下的节点都有一个固定长度的连接列队。如果连接已经被TCP接受(完成三次握手),但未被程序接受,应用程序会对这一列队做出限制,通常称为未完成连接。 | 128 | 1024 |
注意:调整内核参数后内核处于不稳定状态,请务必重启实例。
更多内容后期补充...