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

9
在下面的命令中,我启用了文件/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确定的吗?还是系统默认值?最后,有没有方法可以减少这个超时值?


Stack Overflow是一个关于编程和开发问题的网站。这个问题似乎不属于编程或开发范畴。请参阅帮助中心中的我可以在这里问什么样的问题。也许超级用户Unix&Linux Stack Exchange更适合提问。 - jww
3个回答

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 了解更多选项。

2
这应该是被接受的答案,而不是改变值(不推荐),在 /proc/sys/net/ipv4/tcp_keepalive_time 上广泛使用系统,了解将信号发送给打开套接字进程的父进程将关闭它。我想知道为什么这样做可以工作,而 $ timeout 1 </dev/tcp/stackoverflow.com/81 && echo Port open. 不行。 - Alan Garrido

1

不行:使用/dev/tcp/无法更改超时时间

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

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

您可以查看源代码(请参见:Bash主页),您可能会找到lib/sh/netopen.c文件,在其中可以阅读_netopen4函数:

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

你可以仔细阅读这个文件,但是没有考虑连接超时的问题。
没有修补bash源代码的情况下,无法通过bash脚本更改连接超时时间。
使用netcat(几乎纯bash)的简单HTTP客户端
这里有一个小的HTTP客户端示例,使用bash编写,但使用了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>&-

3
Bash 绝对是一种编程语言。虽然在网络方面的功能不太强大,但这并不是重点。 - tripleee
2
嗯,马铃薯还是土豆无所谓。如果您的标准是某些事情不方便,那么Pascal和Fortran也不是编程语言。C显然更通用,但这也意味着许多事情比专门的语言不方便。 - tripleee
@tripleee,你尝试运行ascii-clock.sh几个小时并检查内存使用情况了吗?(左上角的大写字母S表示休眠,你可以与其他版本进行比较,例如程序员专属:字符画模拟时钟)。 - F. Hauri - Give Up GitHub
像那样的内存漏洞确实很糟糕,但它只是一个实现细节。如果他们解决了这个问题,你会改变你的看法吗? - tripleee
@tripleee 我可以通过每秒运行子任务来解决这个问题,但是bash缺乏变量类型、内存垃圾和许多其他在任何编程语言中都存在的东西。我坚持认为:编程语言和命令语言都是必需的,但并不相同。(我见过一些用php编写的安装脚本!那也太可怕了吧!)... 是的:你可以用刀子抓东西,用叉子切东西... 但这并不是更简单的方法! - F. Hauri - Give Up GitHub
显示剩余2条评论

1

这取决于TCP,应用程序代码可以在每个套接字上降低它。

注意:如果完全没有响应,则超时才会生效。如果连接被拒绝,错误会立即发生。


1
我明白了。在bash中也有可能减少这个吗?我猜不行吧.. 可能只能在Cpython和其他编程语言中实现吧? - Martin
2
我不知道有任何这样的bash设置。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接