日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

tcp連接一端在進行完三次握手以后進入ESTABLISHED狀態(tài),如果連接的對端在某一時刻在網(wǎng)絡中消失,而本端沒有感知到,還是處于ESTABLISHED狀態(tài),那么本端的連接就被稱為半打開連接(Half Open)。

連接的對端在網(wǎng)絡中消失的情況有好多:

例如對端主機突然斷電,tcp連接來不及發(fā)送任何信息就消失啦。

還有,連接路徑上的某個nat設備aging-time過期,并且nat port被重用,雖然tcp連接的兩端都還處于ESTABLISHED狀態(tài),可實際上兩端的連接已經(jīng)無法正常通信,此時這兩端的連接都是半打開連接。(這種情況是我的猜測,還沒有得到實踐的檢驗。如果結論錯誤,就會修改掉!)

還有,listen socket的accept調用緩慢導致積壓隊列滿,client端連接會成為半打開連接。這種情況是本次討論的主題。

 

首先說下tcp的三次握手

淺談tcp的半打開連接

 


server端的tcp連接在三次握手階段會經(jīng)歷SYN_RECV狀態(tài)到ESTABLISHED狀態(tài)的變遷,其中SYN_RECV狀態(tài)到連接存放于listen socket積壓隊列的半連接隊列中,當連接由SYN_RECV狀態(tài)變?yōu)镋STABLISHED狀態(tài),連接會被從半連接隊列中移到已連接隊列中。系統(tǒng)調用accept的作用就是從listen socket的已連接隊列中取走一個連接,然后將該連接與進程綁定。

但是,如果listen socket的積壓隊列(半連接隊列與連接隊列)全部滿后,對于新來的client連接會如何處理呢。答案是,linux不同版本的實現(xiàn)不同。

當前的實驗環(huán)境:

zuchunlei@ubuntu14:~$ uname -a
Linux ubuntu14 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:07:32 UTC 2016 x86_64 x86_64 x86

服務端代碼:

In [1]: from socket import *
In [2]: sock = socket(AF_INET,SOCK_STREAM)
In [3]: sock.bind(("",10000))
In [4]: sock.listen(1)

為了簡單,我將listen的backlog設置為1,并且不調用sock.accept方法。這樣所有的ESTABLISHED狀態(tài)的連接都存在積壓隊列中,并且沒有和進程綁定起來。

使用netstat查看10000端口的狀態(tài):

Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/p                                                                                                                                Sat Dec 16 20:23:03 2017

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 0.0.0.0:10000           0.0.0.0:*               LISTEN      1578/Python      off (0.00/0/0)

使用ss查看10000端口的狀態(tài):

Every 1.0s: ss -tnpoa|sed -n -e 1p -e /10000/p                                                                                                                                          Sat Dec 16 20:25:18 2017

State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
LISTEN     0      1                         *:10000                    *:*      users:(("ipython",1578,6))

解析一下,ss命令輸出的State=Listen狀態(tài)的數(shù)據(jù)時,其中Send-Q的大小表示該listen socket積壓隊列的長度,Recv-Q代表已完成三次握手,ESTABLISHED狀態(tài)的連接個數(shù)。這樣的連接存在于listen socket的已連接隊列中。

用nc localhost 10000進行2次連接后,使用netstat查看10000端口的狀態(tài):

Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/p                                                                                                                                Sat Dec 16 20:32:45 2017

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 0.0.0.0:10000           0.0.0.0:*               LISTEN      1578/python      off (0.00/0/0)
tcp        0      0 127.0.0.1:59890         127.0.0.1:10000         ESTABLISHED 6301/nc          off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:59890         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:59892         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:59892         127.0.0.1:10000         ESTABLISHED 6379/nc          off (0.00/0/0)

netstat顯示當前客戶端程序nc連接已經(jīng)建立完成,服務端的2個連接也處于ESTABLISHED狀態(tài),但因為當前沒有accept調用,所以服務端的兩個連接的進程PID顯示為-,表示當前連接沒有和進程綁定起來。

使用ss查看10000端口的狀態(tài):

Every 1.0s: ss -tnpoa|sed -n -e 1p -e /10000/p                                                                                                                                          Sat Dec 16 20:36:10 2017

State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
LISTEN     2      1                         *:10000                    *:*      users:(("ipython",1578,6))
ESTAB      0      0                 127.0.0.1:59890            127.0.0.1:10000  users:(("nc",6301,3))
ESTAB      0      0                 127.0.0.1:10000            127.0.0.1:59890
ESTAB      0      0                 127.0.0.1:10000            127.0.0.1:59892
ESTAB      0      0                 127.0.0.1:59892            127.0.0.1:10000  users:(("nc",6379,3))

通過ss可以看到,當前LISTEN狀態(tài)的RECV-Q值為2,表示有2個ESTABLISHED狀態(tài)的連接在已連接隊列中等待應用層調用accept取走。

用nc localhost 10000進行第三次連接后,netstat查看10000端口的狀態(tài):

Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/p                                                                                                                                Sat Dec 16 20:41:18 2017

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 0.0.0.0:10000           0.0.0.0:*               LISTEN      1578/python      off (0.00/0/0)
tcp        0      0 127.0.0.1:59890         127.0.0.1:10000         ESTABLISHED 6301/nc          off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:59896         SYN_RECV    -                on (1.06/3/0)
tcp        0      0 127.0.0.1:59896         127.0.0.1:10000         ESTABLISHED 10989/nc         off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:59890         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:59892         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:59892         127.0.0.1:10000         ESTABLISHED 6379/nc          off (0.00/0/0)

可以看到對于第三個客戶端nc,連接狀態(tài)為ESTABLISHED,表示3次握手已經(jīng)正確完成。而對于服務端,當前的連接狀態(tài)為SYN_RECV,表示半連接狀態(tài),因為當前積壓隊列已經(jīng)滿,沒有空間再存放ESTABLISHED連接,所以該連接無法從SYN_RECV狀態(tài)變?yōu)镋STABLISHED狀態(tài),雖然能正確接收到nc端的第三個ACK段。

此時使用tcpdump進行抓包:

zuchunlei@ubuntu14:~$ sudo tcpdump -i any tcp port 10000 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
20:50:15.739292 IP 127.0.0.1.10000 > 127.0.0.1.59896: Flags [S.], seq 2458870060, ack 3925261891, win 43690, options [mss 65495,sackOK,TS val 1340001 ecr 1339751,nop,wscale 7], length 0
20:50:15.739301 IP 127.0.0.1.59896 > 127.0.0.1.10000: Flags [.], ack 1, win 342, options [nop,nop,TS val 1340001 ecr 1339751], length 0
20:50:17.738724 IP 127.0.0.1.10000 > 127.0.0.1.59896: Flags [S.], seq 2458870060, ack 3925261891, win 43690, options [mss 65495,sackOK,TS val 1340501 ecr 1340001,nop,wscale 7], length 0
20:50:17.738772 IP 127.0.0.1.59896 > 127.0.0.1.10000: Flags [.], ack 1, win 342, options [nop,nop,TS val 1340501 ecr 1339751], length 0
20:50:21.739110 IP 127.0.0.1.10000 > 127.0.0.1.59896: Flags [S.], seq 2458870060, ack 3925261891, win 43690, options [mss 65495,sackOK,TS val 1341501 ecr 1340501,nop,wscale 7], length 0
20:50:21.739158 IP 127.0.0.1.59896 > 127.0.0.1.10000: Flags [.], ack 1, win 342, options [nop,nop,TS val 1341501 ecr 1339751], length 0
20:50:29.738975 IP 127.0.0.1.10000 > 127.0.0.1.59896: Flags [S.], seq 2458870060, ack 3925261891, win 43690, options [mss 65495,sackOK,TS val 1343501 ecr 1341501,nop,wscale 7], length 0
20:50:29.739022 IP 127.0.0.1.59896 > 127.0.0.1.10000: Flags [.], ack 1, win 342, options [nop,nop,TS val 1343501 ecr 1339751], length 0
20:50:45.739231 IP 127.0.0.1.10000 > 127.0.0.1.59896: Flags [S.], seq 2458870060, ack 3925261891, win 43690, options [mss 65495,sackOK,TS val 1347501 ecr 1343501,nop,wscale 7], length 0
20:50:45.739310 IP 127.0.0.1.59896 > 127.0.0.1.10000: Flags [.], ack 1, win 342, options [nop,nop,TS val 1347501 ecr 1339751], length 0

對于SYN_RECV狀態(tài)的連接,linux會啟動定時器進行重傳三次握手的第二段[S.],在4次重傳后,如果當前l(fā)isten socket已連接隊列中依然沒有空間,則將SYN_RECV狀態(tài)的連接丟棄。

等待4次重傳后,使用netstat查看10000端口狀態(tài):

Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/p                                                                                                                                Sat Dec 16 20:58:20 2017

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 0.0.0.0:10000           0.0.0.0:*               LISTEN      1578/python      off (0.00/0/0)
tcp        0      0 127.0.0.1:59890         127.0.0.1:10000         ESTABLISHED 6301/nc          off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:59890         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:59896         127.0.0.1:10000         ESTABLISHED 15954/nc         off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:59892         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:59892         127.0.0.1:10000         ESTABLISHED 6379/nc          off (0.00/0/0)

server端將SYN_RECV狀態(tài)的連接丟棄后,此時第三個nc客戶端連接就已經(jīng)成為了半打開連接。

 

對半打開連接進行send/recv操作時的影響:

如果此時,第三個nc客戶端發(fā)送數(shù)據(jù),則因為連接對對端不存在,對端會回復RST段,本端收到RST段后也會將連接重置。

如果第三個nc客戶端只接收數(shù)據(jù)的話,則這個客戶端永遠阻塞在recv調用中無法返回。為了有效解決這種問題,客戶端可以啟動tcp的keepalive,因為默認tcp發(fā)送keepalive probe的間隔時間較長,應用可以通過設置socket option(
TCP_KEEPDILE/TCP_KEEPINTVL/TCP_KEEPCNT)將發(fā)送keepalive probe的時間設短些。

 

今早我測試了一下最新版ubuntu16.04的實現(xiàn),發(fā)現(xiàn)如果listen socket的積壓隊列滿后,新來客戶端的連接不再成為ESTABLISHED狀態(tài),而是在SYN_SENT狀態(tài)進行進行SYN段的超時重傳,而服務端不返回任何tcp段。

新版的測試環(huán)境:

zuchunlei@box:~$ uname -a
Linux box 4.10.0-28-generic #32~16.04.2-Ubuntu SMP Thu Jul 20 10:19:48 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

與之前的測試場景一樣,當前只關注第三個nc客戶端連接的狀態(tài)。

使用netstat查看10000端口的狀態(tài):

Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/p                                                                                                                                Sat Dec 16 21:21:57 2017

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 0.0.0.0:10000           0.0.0.0:*               LISTEN      2022/python      off (0.00/0/0)
tcp        0      0 127.0.0.1:36516         127.0.0.1:10000         ESTABLISHED 2347/nc          off (0.00/0/0)
tcp        0      1 127.0.0.1:36520         127.0.0.1:10000         SYN_SENT    2522/nc          on (5.18/3/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:36518         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:36518         127.0.0.1:10000         ESTABLISHED 2388/nc          off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:36516         ESTABLISHED -                off (0.00/0/0)

此時,第三個nc客戶端連接狀態(tài)為SYN_SENT,進行超時重傳SYN段。

使用tcpdump抓去第三個nc客戶端的tcp包:

zuchunlei@box:~$ sudo tcpdump -i any tcp port 10000 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
21:21:47.357226 IP 127.0.0.1.36520 > 127.0.0.1.10000: Flags [S], seq 1445936074, win 43690, options [mss 65495,sackOK,TS val 4214107076 ecr 0,nop,wscale 7], length 0
21:21:48.358267 IP 127.0.0.1.36520 > 127.0.0.1.10000: Flags [S], seq 1445936074, win 43690, options [mss 65495,sackOK,TS val 4214107327 ecr 0,nop,wscale 7], length 0
21:21:50.373837 IP 127.0.0.1.36520 > 127.0.0.1.10000: Flags [S], seq 1445936074, win 43690, options [mss 65495,sackOK,TS val 4214107831 ecr 0,nop,wscale 7], length 0
21:21:54.565832 IP 127.0.0.1.36520 > 127.0.0.1.10000: Flags [S], seq 1445936074, win 43690, options [mss 65495,sackOK,TS val 4214108879 ecr 0,nop,wscale 7], length 0
21:22:02.758111 IP 127.0.0.1.36520 > 127.0.0.1.10000: Flags [S], seq 1445936074, win 43690, options [mss 65495,sackOK,TS val 4214110927 ecr 0,nop,wscale 7], length 0
21:22:18.885934 IP 127.0.0.1.36520 > 127.0.0.1.10000: Flags [S], seq 1445936074, win 43690, options [mss 65495,sackOK,TS val 4214114959 ecr 0,nop,wscale 7], length 0
21:22:51.141643 IP 127.0.0.1.36520 > 127.0.0.1.10000: Flags [S], seq 1445936074, win 43690, options [mss 65495,sackOK,TS val 4214123023 ecr 0,nop,wscale 7], length 0

可以看到客戶端在進行超時重傳SYN段的過程中,服務端沒有發(fā)送一個包。

在客戶端SYN_SENT超時后,使用netstat查看10000端口狀態(tài):

Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/p                                                                                                                       Sat Dec 16 21:27:36 2017

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 0.0.0.0:10000           0.0.0.0:*               LISTEN      2022/python      off (0.00/0/0)
tcp        0      0 127.0.0.1:36516         127.0.0.1:10000         ESTABLISHED 2347/nc          off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:36518         ESTABLISHED -                off (0.00/0/0)
tcp        0      0 127.0.0.1:36518         127.0.0.1:10000         ESTABLISHED 2388/nc          off (0.00/0/0)
tcp        0      0 127.0.0.1:10000         127.0.0.1:36516         ESTABLISHED -                off (0.00/0/0)

客戶端連接消失。

 

在當前新版當linux實現(xiàn)中,由于listen socket積壓隊列滿時,新的客戶端連接并不會成為半打開連接,而是在connect調用時進行重傳SYN段,如果達到了SYN_SENT狀態(tài)的閾值后,tcp連接消失,應用層connect調用返回timeout異常!

分享到:
標簽:tcp
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定