TCP--telnet為何在127s後返回?

來源:互聯網
上載者:User

標籤:資源   shell   ssi   pac   方式   nec   tcpdump命令   3.5   win   

背景

近期編寫了監控商務服務器的指令碼,主要原理是用shell指令碼(運行shell的機器稱之為監控機)調用項目組專用的介面測試載入器,對指定的商務服務器進行業務操作,根據介面測試載入器的返回結果判斷商務服務器是否運行正常,並使用crontab設定每分鐘執行一次監控指令碼。

在介面測試載入器啟動前,先使用telnet ip port判斷了商務服務器的連接埠是否開啟。監控工作如期進行著……

然而,當新增對某個商務服務器進行監控時,發現telnet該商務服務器所花費的時間很長,已經超過了1分鐘,這意味著指令碼不能在預定的1分鐘的監控間隔內執行完畢,於是我針對該問題進行了探索和研究。

探索和研究

從一些網頁中得知可在一些特定檔案中設定TMOUT變數來控制telnet的逾時時間,也有網頁中提到可以使用nc命令代替telnet實現同類效果並可以設定逾時時間——還沒來得及作深入瞭解,測試出telnet該商務服務器的所需時間長度:

time telnet 123.59.208.201 62715

 

Trying 123.59.208.201...telnet: connect to address 123.59.208.201: Connection timed outtelnet 123.59.208.201 62715  0.00s user 0.00s system 0% cpu 2:07.29 total

結果顯示時間長度為2:07.29,即127s

常見的逾時時間,應多是分鐘的倍數,如60s、3600s等,又或者應是10的倍數,如30s、200s等。但反覆測試了幾次,均是127s。它的特殊性引起了我的好奇,因為127並非是一個普通的數字,它正是2的7次方-1。於是,我修正了搜尋的方向。終於,從搜尋返回的結果頁中看到了一個連結,原文連結:

http://www.chengweiyang.cn/2017/02/18/linux-connect-timeout/?utm_source=tuicool&utm_medium=referral

這篇文章解決了我此時的疑惑,也開啟了新的探索之旅。

127的由來

使用tcpdump進行抓包,運行如下命令:

sudo tcpdump -i eth0 -nn ‘host 123.59.208.201‘

 

tcpdump: verbose output suppressed, use -v or -vv for full protocol decodelistening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes

再新開啟一個終端視窗,執行telnet命令:

date +%Y%m%d-%H:%M:%S.%N;time telnet 123.59.208.201 62715;date +%Y%m%d-%H:%M:%S.%N;

 

20170526-18:04:23.764397558Trying 123.59.208.201...telnet: connect to address 123.59.208.201: Connection timed outtelnet 123.59.208.201 62715  0.00s user 0.00s system 0% cpu 2:07.22 total20170526-18:06:30.989480391

這時,tcpdump所在的終端會同步輸出telnet命令所產生的資料包資訊:

18:04:23.765507 IP 10.253.4.55.34680 > 123.59.208.201.62715: Flags [S], seq 922947731, win 29200, options [mss 1460,sackOK,TS val 13801993 ecr 0,nop,wscale 7], length 018:04:24.768182 IP 10.253.4.55.34680 > 123.59.208.201.62715: Flags [S], seq 922947731, win 29200, options [mss 1460,sackOK,TS val 13802996 ecr 0,nop,wscale 7], length 018:04:26.772188 IP 10.253.4.55.34680 > 123.59.208.201.62715: Flags [S], seq 922947731, win 29200, options [mss 1460,sackOK,TS val 13805000 ecr 0,nop,wscale 7], length 018:04:30.780189 IP 10.253.4.55.34680 > 123.59.208.201.62715: Flags [S], seq 922947731, win 29200, options [mss 1460,sackOK,TS val 13809008 ecr 0,nop,wscale 7], length 018:04:38.796205 IP 10.253.4.55.34680 > 123.59.208.201.62715: Flags [S], seq 922947731, win 29200, options [mss 1460,sackOK,TS val 13817024 ecr 0,nop,wscale 7], length 018:04:54.828196 IP 10.253.4.55.34680 > 123.59.208.201.62715: Flags [S], seq 922947731, win 29200, options [mss 1460,sackOK,TS val 13833056 ecr 0,nop,wscale 7], length 018:05:26.860210 IP 10.253.4.55.34680 > 123.59.208.201.62715: Flags [S], seq 922947731, win 29200, options [mss 1460,sackOK,TS val 13865088 ecr 0,nop,wscale 7], length 0

  

根據telnet命令的起始時間和tcpdump輸出的時間:

04:23.7604:24.7604:26.7704:30.7804:38.7904:54.8205:26.8606:30.98

不難看出規律:它們的差值(單位s)是雙倍遞增的:1、2、4、8、16、32、64

內部原理tcp逾時與重傳

執行telnet命令,其實是嘗試建立tcp串連的過程。而建立tcp串連時會涉及到兩個概念:一個是RTT,一個是RTO。
RTT (Round-Trip Time) 即,往返時間
RTO (Retransmission Time Out) 即,重傳逾時
上面的時間間隔顯然就是RTO。

建立tcp串連的過程和細節這裡不再贅述,如有需要可以參閱《TCPIP詳解(卷1)》。

根據該監控機的核心的版本,查看了linux的相關代碼:
http://elixir.free-electrons.com/linux/v3.10/source/include/net/tcp.h

#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))

得到:

  1. HZ是1s。所以RTO的最小值是200ms,RTO的最大值是120s,即2分鐘。
  2. tcpdump的結果看,監控機的RTO是1s,原因未知
  3. 根據代碼中的演算法部分可知,RTO重傳間隔是指數增加的,隨著重傳次數的增多,消耗的時間指數增長。當RTO小於TCP_RTO_MAX時,則RTO每次翻倍,當超過TCP_RTO_MAX之後,不再翻倍,而是固定用TCP_RTO_MAX,即2分鐘。

而,linux核心變數net.ipv4.tcp_syn_retries用來告訴核心,當嘗試建立一個TCP串連時,要重新發送多少次初始的SYN報文。可以通過 sysctl 命令查看。

查看變數 tcp_syn_retries的值
sudo sysctl net.ipv4.tcp_syn_retries

  

net.ipv4.tcp_syn_retries = 6

因為tcp_syn_retries控制的是重新發送的次數,所以加上初始的那1次,所以上述tcpdump的輸出中一共有7條。

設定變數 tcp_syn_retries的值

設定net.ipv4.tcp_syn_retries並測試telnet的時間長度:

sudo sysctl net.ipv4.tcp_syn_retries=1

  

net.ipv4.tcp_syn_retries = 1

  

驗證:

time telnet 123.59.208.201 62715

  

Trying 123.59.208.201...telnet: connect to address 123.59.208.201: Connection timed outtelnet 123.59.208.201 62715  0.00s user 0.00s system 0% cpu 3.008 total

  

可見,net.ipv4.tcp_syn_retries = 1時,telnet的耗時約為3s。可以預知的是,如果用tcpdump抓包,應當有兩條,而3s則是RTO分別取1s和2s的結果。

sudo sysctl net.ipv4.tcp_syn_retries=2

  

net.ipv4.tcp_syn_retries = 2

  

time telnet 123.59.208.201 62715

  

Trying 123.59.208.201...telnet: connect to address 123.59.208.201: Connection timed outtelnet 123.59.208.201 62715  0.00s user 0.00s system 0% cpu 7.010 total

  

net.ipv4.tcp_syn_retries = 2時,telnet的耗時約為7s,遵守RTO指數遞增規律。

sudo sysctl net.ipv4.tcp_syn_retries=5

  

net.ipv4.tcp_syn_retries = 5

  

time telnet 123.59.208.201 62715

  

Trying 123.59.208.201...telnet: connect to address 123.59.208.201: Connection timed outtelnet 123.59.208.201 62715  0.00s user 0.00s system 0% cpu 1:03.14 total

  

net.ipv4.tcp_syn_retries = 5時,telnet的耗時約為63s,遵守RTO指數遞增規律。

那麼,按照RTO指數遞增規律和TCP_RTO_MAX的設定,當net.ipv4.tcp_syn_retries持續增大時,RTO並不會對應地指數遞增下去,把net.ipv4.tcp_syn_retries設定成10看看效果:

sudo sysctl net.ipv4.tcp_syn_retries=10

  

net.ipv4.tcp_syn_retries = 10

  

驗證:

date +%Y%m%d-%H:%M:%S.%N;time telnet 123.59.208.201 62715;date +%Y%m%d-%H:%M:%S.%N;

  

20170526-18:47:25.899074041Trying 123.59.208.201...telnet: connect to address 123.59.208.201: Connection timed outtelnet 123.59.208.201 62715  0.00s user 0.00s system 0% cpu 10:08.64 total20170526-18:57:34.541575652

  

查看tcpdump的結果:

18:47:25.900294 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16384128 ecr 0,nop,wscale 7], length 018:47:26.902184 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16385130 ecr 0,nop,wscale 7], length 018:47:28.908195 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16387136 ecr 0,nop,wscale 7], length 018:47:32.916178 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16391144 ecr 0,nop,wscale 7], length 018:47:40.940213 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16399168 ecr 0,nop,wscale 7], length 018:47:56.972221 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16415200 ecr 0,nop,wscale 7], length 018:48:29.004213 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16447232 ecr 0,nop,wscale 7], length 018:49:33.132192 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16511360 ecr 0,nop,wscale 7], length 018:51:33.580213 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16631808 ecr 0,nop,wscale 7], length 018:53:33.900217 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16752128 ecr 0,nop,wscale 7], length 018:55:34.220216 IP 10.253.4.55.36266 > 123.59.208.201.62715: Flags [S], seq 3545463057, win 29200, options [mss 1460,sackOK,TS val 16872448 ecr 0,nop,wscale 7], length 0

  

當RTO18:48:29.00 -> 18:49:33.13到達64s後,下一次按照遞增規則應當變為128s,而實際上,18:49:33.13 -> 18:51:33.58 -> 18:53:33.90 -> 18:55:34.22,RTO變為恒定的120s(TCP_RTO_MAX)。

取值範圍

設定成0次會報錯:

sudo sysctl net.ipv4.tcp_syn_retries=0

  

sysctl: setting key "net.ipv4.tcp_syn_retries": Invalid argumentnet.ipv4.tcp_syn_retries = 0

  

不少網頁上提到net.ipv4.tcp_syn_retries的最大值可設定為255、預設值是5,在這台監控機上實測發現最大隻能設定為127:

sudo sysctl net.ipv4.tcp_syn_retries=127

  

net.ipv4.tcp_syn_retries = 127

嘗試設定成128時保錯:

sudo sysctl net.ipv4.tcp_syn_retries=128

  

sysctl: setting key "net.ipv4.tcp_syn_retries": Invalid argumentnet.ipv4.tcp_syn_retries = 128

  

在linux核心的相關網頁上有明確記錄——最大不超過127、預設值為6
https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

tcp_syn_retries - INTEGER
Number of times initial SYNs for an active TCP connection attempt
will be retransmitted. Should not be higher than 127. Default value
is 6, which corresponds to 63seconds till the last retransmission
with the current initial RTO of 1second. With this the final timeout
for an active TCP connection attempt will happen after 127seconds.

但,指出net.ipv4.tcp_syn_retries的最大值可設定為255的網頁中,有不少網頁看起來也具有一定的可信度,比如:

https://www.frozentux.net/ipsysctl-tutorial/chunkyhtml/tcpvariables.html

3.3.24. tcp_syn_retries
The tcp_syn_retries variable tells the kernel how many times to try to retransmit the initial SYN packet for an active TCP connection attempt.
This variable takes an integer value, but should not be set higher than 255 since each retransmission will consume huge amounts of time as well as some amounts of bandwidth. Each connection retransmission takes aproximately 30-40 seconds. The default setting is 5, which would lead to an aproximate of 180 seconds delay before the connection times out.

隨著根據實測結果和網站的權威性,我更信賴最大不超過127、預設值為6,但同時也很好奇,這些網頁的內容依據出自何處?

永久修改

上述提到的修改net.ipv4.tcp_syn_retries的方式均是臨時修改,重啟系統後便失效。若想永久生效,則需要修改相應的設定檔,請自行搜尋。

另外,因為變數net.ipv4.tcp_syn_retries是系統範圍的,而它影響tcp建立串連的重傳次數,所以修改前建議與系統管理員確認。

總結

美其名曰探索和研究,實際就是在踩自己因為基礎知識欠缺而埋下的坑

雖然搞清楚了127的由來,但卻帶來了許多新的疑問和不解,作為下一次踩坑的引子。

參考連結

踩坑的過程,總能發現一些不錯的資源網站,如:

  1. https://www.kernel.org
  2. http://lxr.linux.no/
  3. http://free-electrons.com/docs/

我想,這算得上對困而學之者的最好獎勵了。大概也是為了讓我能夠成為學而知之者吧。

相關知識
  • tcp協議
  • tcpdump命令
  • sysctl命令
  • telnet命令

TCP--telnet為何在127s後返回?

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.