网络基础-TCP协议握手与挥手

发布于:2024-04-18 ⋅ 阅读:(19) ⋅ 点赞:(0)

简单回顾一下TCP三次握手和四次挥手过程

详细介绍一下三次握手 我们可以看到 syns queue和accept queue队列来接收和处理消息的。

TCP三次握手时,Linux内核会维护两个队列

1、半连接队列,被称为SYN队列

2、全连接队列,被称为 accept队列

介绍一下整体过程

1、客户端发送SYN包,并进入SYN_SENT状态

2、服务端接收到数据包将相关信息放入半连接队列(SYNS 队列),并返回SYC+ACK包给客户端。

3、服务端接收客户端ACK数据包,这时如果全连接队列(accept 队列)没满,就会从半连接队列里面        将数据取出来放入全连接队列,等待应用使用,当队列已满就会跟据tcpaborton_overflow
       配置执行策略。

TCP三次握手队列

  • client端的socket等待队列:

当第一次握手,建立半连接状态:client 通过 connect 向 server 发出 SYN 包时,client 会维护一个 socket 队列,如果 socket 等待队列满了,而 client 也会由此返回 connection time out,只要是 client 没有收到 第二次握手SYN+ACK,3s 之后,client 会再次发送,如果依然没有收到,9s 之后会继续发送。

  • server端的半连接队列(syn队列):

此时server 会维护一个 SYN 队列,半连接 syn 队列的长度为 max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)  ,在机器的tcp_max_syn_backlog值在/proc/sys/net/ipv4/tcp_max_syn_backlog下配置,当 server 收到 client 的 SYN 包后,会进行第二次握手发送SYN+ACK 的包加以确认,client 的 TCP 协议栈会唤醒 socket 等待队列,发出 connect 调用。

  • server端的完全连接队列(accpet队列):

当第三次握手时,当server接收到ACK 报之后, 会进入一个新的叫 accept 的队列,该队列的长度为 min(backlog, somaxconn),默认情况下,somaxconn 的值为 128,表示最多有 129 的 ESTAB 的连接等待 accept(),而 backlog 的值则应该是由 int listen(int sockfd, int backlog) 中的第二个参数指定,listen 里面的 backlog 可以有我们的应用程序去定义的。

如何查看队列信息?

1.netstat

2.netstat -an |grep tcp 只查看TCP连接

3.netstat -an |grep ESTABLISHED 查看连接状态数据

4. netstat | grep "l-db1.dba.cn" 过滤应用

5.netstat -an | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 如果需要统计tcp连接每种状态的连接的数量

6.sudo netstat -natp | grep SYN_RECV | wc -l 查看半连接数量

7.sudo netstat -natp | grep ESTABLISHED | wc -l 查看全连接数量

8.netstat -s | egrep "listen|LISTEN" 看是否全连接队列溢出

当有大量请求进入,如果TCP全连接队列过小的话就会出现全连接队列溢出,当出现全连接队列溢出现象的时候,后续的请求就会被丢弃,就会出现服务请求数量上不去的现象。

表示全连接队列溢出的次数,隔几秒查询一次,如果这个数字一直在递增,说明全连接队列出现了溢出的状态

怎么配置溢出策略?

前面提到在TCP三次握手的最后一步,当全连接队列已满就会根据tcpabortonoverflow策略进行处理。Linux 可通过 /proc/sys/net/ipv4/tcpabortonoverflow 进行配置。

1、当tcpabortonoverflow=0,服务accept 队列满了,客户端发来ack,服务端直接丢弃该ACK,此时服务端处于【synrcvd】的状态,客户端处于【established】的状态。在该状态下会有一个定时器重传服务端 SYN/ACK 给客户端

(不超过 /proc/sys/net/ipv4/tcpsynackretries 指定的次数,Linux下默认5)。

超过后,服务器不在重传,后续也不会有任何动作。如果此时客户端发送数据过来,服务端会返回RST。(这也就是我们的异常原因了)

2、当tcpaborton_overflow=1,服务端accept队列满了,客户端发来ack,服务端直接返回RST通知client,表示废掉这个握手过程和这个连接,client会报connection reset by peer。

配置全连接队列和半连接队列大小?

全连接队列大小取决于backlog 和somaxconn 的最小值,也就是 min(backlog,somaxconn)

1、somaxconn 是Linux内核参数,默认128,可通过/proc/sys/net/core/somaxconn进行配置

2、backlog是 listen(int sockfd,int backlog)函数中的参数backlog,Tomcat 默认100,Nginx 默认511.

半连接队列的长度可以通过 /proc/sys/net/ipv4/tcpmaxsyn_backlog来设置.os层面,只能设一个,由所有程序共享)

参考:
面试官:换人!他连 TCP 这几个参数都不懂

再谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP - Network - 周陆军的个人网站

硬不硬你说了算!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题