1. 程式人生 > >Tcp超時修改

Tcp超時修改

linux 系統 nec 以及 host sel dump back col 並不是

Linux 建立 TCP 連接的超時時間分析

tags: linux | network

Linux 系統默認的建立 TCP 連接的超時時間為 127 秒,對於許多客戶端來說,這個時間都太長了, 特別是當這個客戶端實際上是一個服務的時候,更希望能夠盡早失敗,以便能夠選擇其它的可用服務重新嘗試。

socket 是 Linux 下實現的傳輸控制層協議,包括 TCP 和 UDP,一個 socket 端點由 IP 和端口對來唯一標識; 如果開啟了地址復用,那麽可以進一步由協議,IP 和端口來唯一標識。

系統調用 connect(2) 則是用來嘗試建立 socket 連接(TCP)或者和遠程協商一致(UDP)的函數。 connect 對於 UDP 來說並不是必須的,而對於 TCP 來說則是一個必須過程,註明的 TCP 3 次握手實際上也由 connect 來完成。

註:這裏只分析 TCP 連接超時

網絡中的連接超時非常常見,不管是廣域網還是局域網,為了一定程度上容忍失敗,所以連接加入了重試機制, 而另一方面,為了不給服務端帶來過大的壓力,重試也是有限制的。

在 Linux 中,連接超時典型為 2 分 7 秒,而對於一些 client 來說,這是一個非常長的時間; 所以在編程中,可以使用非阻塞的方式來實現,例如:使用 poll(2), epoll(2), select(2) 等系統調用來實現多路復用等待。

下面來看看 2 分 7 秒是怎樣來的,以及怎樣配置 Linux kernel 來縮短這個超時。

這裏的net.ipv4.tcp_syn_retries

的值等於n 的話,也就是說tcp的鏈接超時時間是2的n+1次方減1

2 分 7 秒


2 分 7 秒即 127 秒,剛好是 2 的 7 次方減一,聰明的讀者可能已經看出來了,如果 TCP 握手的 SYN 包超時重試按照 2 的冪來 backoff, 那麽:

  1. 第 1 次發送 SYN 報文後等待 1s(2 的 0 次冪),如果超時,則重試
  2. 第 2 次發送後等待 2s(2 的 1 次冪),如果超時,則重試
  3. 第 3 次發送後等待 4s(2 的 2 次冪),如果超時,則重試
  4. 第 4 次發送後等待 8s(2 的 3 次冪),如果超時,則重試
  5. 第 5 次發送後等待 16s(2 的 4 次冪),如果超時,則重試
  6. 第 6 次發送後等待 32s(2 的 5 次冪),如果超時,則重試
  7. 第 7 次發送後等待 64s(2 的 6 次冪),如果超時,則超時失敗

上面的結果剛好是 127 秒。也就是說 Linux 內核在嘗試建立 TCP 連接時,最多會嘗試 7 次。

那麽下面通過具體方法來驗證。

首先,配置 iptables 來丟棄指定端口的 SYN 報文

# iptables -A INPUT --protocol tcp --dport 5000 --syn -j DROP

然後,打開 tcpdump 觀察到達指定端口的報文

# tcpdump -i lo -Ss0 -n src 127.0.0.1 and dst 127.0.0.1 and port 5000

最後,使用 telnet 連接指定端口

$ date; telnet 127.0.0.1 5000; date

上面命令的輸出如下:

Tue Jan  3 16:39:05 CST 2017
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection timed out
Tue Jan  3 16:41:12 CST 2017

而從 tcpdump 命令的輸出可以看到:

16:39:05.690238 IP 127.0.0.1.58933 > 127.0.0.1.5000: Flags [S], seq 2286786481, win 43690, options [mss 65495,sackOK,TS val 179222486 ecr 0,nop,wscale 7], length 0
16:39:06.686988 IP 127.0.0.1.58933 > 127.0.0.1.5000: Flags [S], seq 2286786481, win 43690, options [mss 65495,sackOK,TS val 179222736 ecr 0,nop,wscale 7], length 0
16:39:08.690980 IP 127.0.0.1.58933 > 127.0.0.1.5000: Flags [S], seq 2286786481, win 43690, options [mss 65495,sackOK,TS val 179223237 ecr 0,nop,wscale 7], length 0
16:39:12.702973 IP 127.0.0.1.58933 > 127.0.0.1.5000: Flags [S], seq 2286786481, win 43690, options [mss 65495,sackOK,TS val 179224240 ecr 0,nop,wscale 7], length 0
16:39:20.718991 IP 127.0.0.1.58933 > 127.0.0.1.5000: Flags [S], seq 2286786481, win 43690, options [mss 65495,sackOK,TS val 179226244 ecr 0,nop,wscale 7], length 0
16:39:36.766986 IP 127.0.0.1.58933 > 127.0.0.1.5000: Flags [S], seq 2286786481, win 43690, options [mss 65495,sackOK,TS val 179230256 ecr 0,nop,wscale 7], length 0
16:40:08.830996 IP 127.0.0.1.58933 > 127.0.0.1.5000: Flags [S], seq 2286786481, win 43690, options [mss 65495,sackOK,TS val 179238272 ecr 0,nop,wscale 7], length 0

其中,Flags [S] 表示為 SYN 報文,可以看到總共發送了 7 次 SYN 報文,最後一次的時間為 16:40:08,而 telnet 超時退出的時間為 16:41:12,相差 64 秒。

怎樣修改 connect timeout


對於很多客戶端程序來說,127 秒都是一個很長的時間,特別是對於局域網來說,公司內部往往都具有網絡質量較好的局域網, 訪問內部的服務並不需要等待這麽長的超時,而可以 fail earlier。

Linux 內核中,net.ipv4.tcp_syn_retries 表示建立 TCP 連接時 SYN 報文重試的次數,默認為 6,可以通過 sysctl 命令查看。

# sysctl -a | grep tcp_syn_retries
net.ipv4.tcp_syn_retries = 6

將其修改為 1,則可以將 connect 超時時間改為 3 秒,例如:

# sysctl net.ipv4.tcp_syn_retries=1

再次使用 telnet 驗證超時時間,如下:

$ date; telnet 127.0.0.1 5000; date
Fri Feb 17 09:50:12 CST 2017
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection timed out
Fri Feb 17 09:50:15 CST 2017

註意:sysctl 修改的內核參數在系統重啟後失效,如果需要持久化,可以修改系統配置文件

例如:,對於 CentOS 7 來說,添加 net.ipv4.tcp_syn_retries = 1 到 /etc/sysctl.conf 中即可。

原文章:http://www.chengweiyang.cn/2017/02/18/linux-connect-timeout/

Tcp超時修改