网络编程之每天学习一点点[day6]-----tcp三次握手和backlog

先看一副图:



在linux2.2之前

linux内核在底层维护一个由backlog指定大小的队列。

客户端发送SYN(第一次握手),服务端收到SYN后,返回一个SYN/ACK(第二次握手),并把连接放入队列中,此时这个连接的状态是SYN_RECEIVED。当客户端返回ACK后(第三次握手),此连接的状态变为ESTABLISHED。队列中只有ESTABLISHED状态的连接能够交由应用程序处理。

当队列满了以后,服务端再收到来自客户端发起的SYN握手请求时,将不会返回SYN/ACK。比较优雅的处理方法就是不处理这条连接,不返回RST响应结果,让客户端重试。

简单概括为:一个队列,两种状态。


在linux2.2之后:

在底层维护一个SYN_RECEIVED队列和一个ESTABLISHED队列,当SYN_RECEIVED队列中(syn queue)的连接对应的客户端返回ACK后(三次握手完成),将被移动到ESTABLISHED队列中。backlog指的是ESTABLISHED队列(accept queue)的大小。

SYN_RECEIVED 队列即syn queue大小:由proc/sys/net/ipv4/tcp_max_syn_backlog系统参数指定,默认2048.

ESTABLISHED队列即accept queue大小:由backlog和/proc/sys/net/core/somaxconn(默认128,或者在 /etc/sysctl.conf 中配置 net.core.somaxconn = 128)中较小的指定。



ss命令查看下http的队列状态:

Netid  State      Recv-Q Send-Q Local Address:Port                 Peer Address:Port 


看到监听的https的队列状态:

Send-Q即Accept queue的最大值128.

Recv-Q为0,表示Accept queue中等待被服务器从accept队列中拿出的数量。


SYN queue 溢出



Accept queue 溢出


案例:backlog设置过小,accept queue溢出造成的

客户端connect返回不代表tcp连接建立成功,即虽然客户端发送syn请求,得到了syn+ack的响应,然后客户端发送ack给服务器,但是由可能此时accept queue溢出,无法将syn queue的半连接移动到accept queue。所以linux操作系统会直接丢弃后续客户端的ACK请求。此时客户端以为连接已经建立,开始发送数据,无法得到服务器响应。


案例:backlog设置过大,客户端关闭连接

backlog设置过大,accept queue队列挤压,连接由于超时而被客户端关闭。


案例:两次握手后,第三次握手握手失败

服务器等待客户端的ack,然后超时,服务器会重新发送SYN+ACK给客户端,重传次数受net.ipv4.tcp_synack_retries限制。如果这个值设置为1,那么只会重传1次,如果这次重传后客户端发送ack仍然失败,客户端将阻塞。如果客户端发送ack成功,则建立established,三次握手成功调用后续recvmsg().







猜你喜欢

转载自blog.csdn.net/shengqianfeng/article/details/80792216