新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Linux協(xié)議棧accept和syn隊(duì)列問(wèn)題

Linux協(xié)議棧accept和syn隊(duì)列問(wèn)題

作者: 時(shí)間:2016-10-08 來(lái)源:網(wǎng)絡(luò) 收藏

161310 cient端收到synack后,根據(jù)ack值,使用SACK算法,只重傳最后一個(gè)ack內(nèi)容。

Server端收到數(shù)據(jù)包,由于accept隊(duì)列仍然是滿的,所以server端處理也只是標(biāo)記acked,然后返回。

162884 client端等待幾秒后,沒(méi)有收到對(duì)應(yīng)的ack,認(rèn)為之前的數(shù)據(jù)包也丟失,所以重傳之前的內(nèi)容數(shù)據(jù)包。

Server端收到數(shù)據(jù)包,由于accept隊(duì)列仍然是滿的,所以server端處理也只是標(biāo)記acked,然后返回。

164828 client端等待一段時(shí)間后,認(rèn)為連接不可用,于是發(fā)送FIN、ACK給server端。Client端的狀態(tài)變?yōu)镕IN_WAIT1,等待一段時(shí)間后,client端將看不到該鏈接。

164829 server端收到ACK后,此時(shí)cgi程序處理完一個(gè)請(qǐng)求,從accept隊(duì)列中取走一個(gè)連接,此時(shí)accept隊(duì)列中有了空閑,server端將請(qǐng)求的連接放到accept隊(duì)列中。

這樣cgi所在的服務(wù)器上顯示該鏈接是established的,但是nginx(client端)所在的服務(wù)器上已經(jīng)沒(méi)有該鏈接了。

之后,當(dāng)cgi程序從accept隊(duì)列中取到該連接后,調(diào)用read去讀取sock中的內(nèi)容,但是由于client端早就退出了,所以read就會(huì)block那里了。

問(wèn)題解決

或許你會(huì)認(rèn)為在164829中,server端不應(yīng)該建立連接,這是內(nèi)核的bug。但是內(nèi)核是按照RFC來(lái)實(shí)現(xiàn)的,在3次握手的過(guò)程中,是不會(huì)判斷FIN標(biāo)志位的,只會(huì)處理SYN、ACK、RST這三種標(biāo)志位。

從應(yīng)用層的角度來(lái)考慮解決問(wèn)題的方法,那就是使用非阻塞的方式read,或者使用select超時(shí)方式read;亦或者nginx中關(guān)閉連接的時(shí)候使用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.


上一頁(yè) 1 2 下一頁(yè)

關(guān)鍵詞:

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉