微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux协议栈accept和syn队列问题

Linux协议栈accept和syn队列问题

时间:10-08 来源:互联网 点击:

synack重传次数在阀值以内,重新发送synack给client端。

152581 cient端收到synack后,根据ack值,使用SACK算法,只重传最后一个ack内容。

Server端收到数据包,由于accept队列仍然是满的,所以server端处理也只是标记acked,然后返回

153455 client端等待3秒后,没有收到对应的ack,认为之前的数据包也丢失,所以重传之前的内容数据包。

155399 server端连接建立定时器生效,遍历半连接链表,发现刚才acked的连接,synack重传次数在阀值以内,重新发送synack给client端。

155400 cient端收到synack后,根据ack值,使用SACK算法,只重传最后一个ack内容。

Server端收到数据包,由于accept队列仍然是满的,所以server端处理也只是标记acked,然后返回。

156468 client端等待几秒后,没有收到对应的ack,认为之前的数据包也丢失,所以重传之前的内容数据包。

161309 server端连接建立定时器生效,遍历半连接链表,发现刚才acked的连接,synack重传次数在阀值以内,重新发送synack给client端。

161310 cient端收到synack后,根据ack值,使用SACK算法,只重传最后一个ack内容。

Server端收到数据包,由于accept队列仍然是满的,所以server端处理也只是标记acked,然后返回。

162884 client端等待几秒后,没有收到对应的ack,认为之前的数据包也丢失,所以重传之前的内容数据包。

Server端收到数据包,由于accept队列仍然是满的,所以server端处理也只是标记acked,然后返回。

164828 client端等待一段时间后,认为连接不可用,于是发送FIN、ACK给server端。Client端的状态变为FIN_WAIT1,等待一段时间后,client端将看不到该链接。

164829 server端收到ACK后,此时cgi程序处理完一个请求,从accept队列中取走一个连接,此时accept队列中有了空闲,server端将请求的连接放到accept队列中。

这样cgi所在的服务器上显示该链接是established的,但是nginx(client端)所在的服务器上已经没有该链接了。

之后,当cgi程序从accept队列中取到该连接后,调用read去读取sock中的内容,但是由于client端早就退出了,所以read就会block那里了。

问题解决

或许你会认为在164829中,server端不应该建立连接,这是内核的bug。但是内核是按照RFC来实现的,在3次握手的过程中,是不会判断FIN标志位的,只会处理SYN、ACK、RST这三种标志位。

从应用层的角度来考虑解决问题的方法,那就是使用非阻塞的方式read,或者使用select超时方式read;亦或者nginx中关闭连接的时候使用RST方式,而不是FIN方式。

附录1

when I use linux TCP socket, and find there is a bug in function sk_acceptq_is_full():

When a new SYN comes, TCP module first checks its validation. If valid,send SYN,ACK to the client and add the sock

to the syn hash table.

Next time if received the valid ACK for SYN,ACK from the client. server will accept this connection and increase the

sk->sk_ack_backlog -- which is done in function tcp_check_req().

We check wether acceptq is full in function tcp_v4_syn_recv_sock().

Consider an example:

After listen(sockfd, 1) system call, sk->sk_max_ack_backlog is set to

As we know, sk->sk_ack_backlog is initialized to 0. Assuming accept() system call is not invoked now

1. 1st connection comes. invoke sk_acceptq_is_full(). sk->sk_ack_backlog=0 sk->sk_max_ack_backlog=1, function return 0 accept this connection. Increase the sk->sk_ack_backlog

2. 2nd connection comes. invoke sk_acceptq_is_full(). sk->sk_ack_backlog=1 sk->sk_max_ack_backlog=1, function return 0 accept this connection. Increase the sk->sk_ack_backlog

3. 3rd connection comes. invoke sk_acceptq_is_full(). sk->sk_ack_backlog=2 sk->sk_max_ack_backlog=1, function return 1. Refuse this connection.I think it has bugs. after listen system call. sk->sk_max_ack_backlog=1

but now it can accept 2 connections.

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top