如何减少 TCP connect() 系统调用超时?

问题描述 投票:0回答:4

在下面的命令中,我启用文件

/dev/tcp/10.10.10.1/80
的读取和写入功能,并将其与文件描述符 3 相关联:

$ time exec 3<>/dev/tcp/10.10.10.1/80
bash: connect: Operation timed out
bash: /dev/tcp/10.10.10.1/80: Operation timed out

real    1m15.151s
user    0m0.000s
sys     0m0.000s

这会自动尝试执行 TCP 三向握手。如果如上例所示无法访问 10.10.10.1,则

connect
系统调用将尝试连接 75 秒。这个75秒的超时是由
bash
决定的吗?或者说这个是系统默认的?最后但并非最不重要的一点是,有没有办法减少这个超时值?

bash tcp connection-timeout
4个回答
13
投票

如前所述,如果不修改源代码,在 Bash 中是不可能的,尽管这里是使用

timeout
命令的解决方法,例如:

$ timeout 1 bash -c "</dev/tcp/stackoverflow.com/80" && echo Port open. || echo Port closed.
Port open.
$ timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.
Port closed.

使用此语法,

timeout
命令将在给定时间后终止进程。

请参阅:

timeout --help
了解更多选项。


1
投票

由TCP决定。可以通过应用程序代码按每个插槽减少它。

NB 只有在完全没有响应的情况下,超时才会生效。如果连接被拒绝,错误会立即发生。


1
投票

否:无法使用
/dev/tcp/

更改超时

是的,您可以使用任何编程语言更改 TCP 连接的默认超时。

但是,不是一种编程语言!

您可以查看源代码(请参阅:Bash Homepage),您可能会找到

lib/sh/netopen.c
文件,您可以在其中读取
_netopen4
函数:

s = socket(AF_INET, (typ == 't') ? SOCK_STREAM : SOCK_DGRAM, 0);

你可以仔细阅读这个文件,没有考虑连接超时。

如果不修补 bash 源,就无法通过 bash 脚本更改连接超时。

使用 netcat 的简单 HTTP 客户端(接近纯 bash)

有一个用 pure bash 编写的 HTTP 客户端示例,但使用

netcat
:

#!/bin/bash

tmpfile=$(mktemp -p $HOME .netbash-XXXXXX)
exec 7> >(nc -w 3 -q 0 stackoverflow.com 80 >$tmpfile)
exec 6<$tmpfile
rm $tmpfile

printf >&7 "GET %s HTTP/1.0\r\nHost: stackoverflow.com\r\n\r\n" \
    /questions/24317341/how-to-decrease-tcp-connect-system-call-timeout

timeout=100;
while ! read -t .001 -u 6 status ; do read -t .001 foo;done
echo STATUS: $status

[ "$status" ] && [ -z "${status//HTTP*200 OK*}" ] || exit 1

echo HEADER:
while read -u 6 -a head && [ "${head//$'\r'}" ]; do
    printf "%-20s : %s\n" ${head%:} "${head[*]:1}"
    done

echo TITLE:
sed '/<title>/s/<[^>]*>//gp;d' <&6

exec 7>&-
exec 6<&-

这可能会呈现:

STATUS: HTTP/1.1 200 OK
HEADER:
Cache-Control        : private
Content-Type         : text/html; charset=utf-8
X-Frame-Options      : SAMEORIGIN
X-Request-Guid       : 46d55dc9-f7fe-425f-a560-fc49d885a5e5
Content-Length       : 91642
Accept-Ranges        : bytes
Date                 : Wed, 19 Oct 2016 13:24:35 GMT
Via                  : 1.1 varnish
Age                  : 0
Connection           : close
X-Served-By          : cache-fra1243-FRA
X-Cache              : MISS
X-Cache-Hits         : 0
X-Timer              : S1476883475.343528,VS0,VE100
X-DNS-Prefetch-Control : off
Set-Cookie           : prov=ff1129e3-7de5-9375-58ee-5f739eb73449; domain=.stackoverflow.com; expires=Fri, 01-Jan-2055 00:00:00 GMT; path=/; HttpOnly
TITLE:
bash - How to decrease TCP connect() system call timeout? - Stack Overflow
一些解释:

我们首先创建一个临时文件(出于安全原因在私有目录下),在使用它们之前绑定并删除。

$ tmpfile=$(mktemp -p $HOME .netbash-XXXXXX)
$ exec 7> >(nc -w 3 -q 0 stackoverflow.com 80 >$tmpfile)
$ exec 6<$tmpfile
$ rm $tmpfile

$ ls $tmpfile
ls: cannot access /home/user/.netbash-rKvpZW: No such file or directory

$ ls -l /proc/self/fd
lrwx------ 1 user user 64 Oct 19 15:20 0 -> /dev/pts/1
lrwx------ 1 user user 64 Oct 19 15:20 1 -> /dev/pts/1
lrwx------ 1 user user 64 Oct 19 15:20 2 -> /dev/pts/1
lr-x------ 1 user user 64 Oct 19 15:20 3 -> /proc/30237/fd
lr-x------ 1 user user 64 Oct 19 15:20 6 -> /home/user/.netbash-rKvpZW (deleted)
l-wx------ 1 user user 64 Oct 19 15:20 7 -> pipe:[2097453]

$ echo GET / HTTP/1.0$'\r\n\r' >&7
$ read -u 6 foo
$ echo $foo
HTTP/1.1 500 Domain Not Found

$ exec 7>&-
$ exec 6>&-

0
投票

在主机级别,您可以通过修改net.ipv4.tcp_syn_retries(默认6)来更改TCP连接超时。您可以通过运行以下命令来实验性地推断指数退避:

# for r in {1..6} ; do sysctl net.ipv4.tcp_syn_retries=$r ; echo predicted: $(( 2**(r+1) - 1 )) ; /bin/time -f %e ./tcp.conn.py ; done
predicted: 3
3.02
net.ipv4.tcp_syn_retries = 2
predicted: 7
7.02
net.ipv4.tcp_syn_retries = 3
predicted: 15
15.03
net.ipv4.tcp_syn_retries = 4
predicted: 31
31.06
net.ipv4.tcp_syn_retries = 5
predicted: 63
63.10
net.ipv4.tcp_syn_retries = 6
predicted: 127
127.22

tcp.conn.py代码:

from socket import create_connection

dest_host = '130.1.1.1'
dest_port = 65432

try:
    create_connection(
        address=(dest_host, dest_port),
    )
except:
    pass

要使 TCP 连接超时尽可能低(3 秒),请运行:

# sysctl net.ipv4.tcp_syn_retries=1
© www.soinside.com 2019 - 2024. All rights reserved.