问题解决系列-wget

--connect-timeout问题处理

Posted by caoyj on April 7, 2024

前言

在最近的一个客户项目中,给客户实现的功能中,我使用了 wget 命令来下载文件。本应在通信故障时依赖于 –connect-timeout 参数来限制连接超时,但我注意到超时时间实际上超出了我所设置的阈值,接下来的这篇文章,用于记录我的问题解决过程。

正文

命令如下:

wget -P --connect-timeout=2s  /tmp/ http://example.com/myfile

现象:该条命令执行了远超过2s的时间,才停止执行。

实际上,我的预期效果是时间达到2s时,该命令由于目标下载地址无法通信,导致wget连接超时退出,显然,当前的命令执行的时间远远超过我设置的2s。

为了解决这个问题我在网上检索解决方案。

1、查看官方文档:

分为timeout、connect-timeout、read-timeout

经过验证,如果把–timeout=参数设置为一个固定值,此时执行wget命令时,一旦时间到达提前设置的timeout阈值,无论下载成功或者失败都会结束命令运行。

根据官方文档内容,如果设置timeout,即包含了完整的请求到下载的所有流程(相当于整个过程从dns解析,建立连接到文件传输等所有过程),均在设定时间内结束,而我的目的是为了在下载之前提前对目标地址是否可以通信做一个判断,一旦开始建立连接,开始下载以后,就不应该在设定一个很短的阈值了,显然如果整个过程2s与当前目标不符合。

2、查询报错信息

命令如下:

strace -o outpu.txt wget -P --connect-timeout=2s  /tmp/ http://example.com/myfile

此命令生成一个访问过程的追踪文件output.txt。

使用python对该文件进行解析:

cat << 'EOF' > parse.py
# -*- coding: utf-8 -*-
import re

interested_syscalls = ['socket', 'connect', 'select']

# 修改正则表达式样式以匹配您感兴趣的信息。
pattern = re.compile(r'(?P<syscall>\w+)\((?P<args>.*)\)\s=\s(?P<result>.*)')

with open('output.txt', 'r') as f:
    for line in f:
        match = pattern.match(line)
        if match and match.group('syscall') in interested_syscalls:
            # 对匹配到的 syscall, args, result 进行处理
            print match.group('syscall'), match.group('args'), match.group('result')
EOF

python parse.py

返回结果集:

[root@db01 tmp]# python parse.py 
socket AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0 3
connect 3, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110 -1 ENOENT (No such file or directory)
socket AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0 3
connect 3, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110 -1 ENOENT (No such file or directory)
socket AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP 3
connect 3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("114.114.114.114")}, 16 0
socket AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP 4
connect 4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("100.95.0.1")}, 16 0
socket AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP 5
connect 5, {sa_family=AF_INET6, sin6_port=htons(53), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "fd00:ec2::250", &sin6_addr), sin6_scope_id=0}, 28 0

关键词进行搜索:

sa_family=AF_UNIX, sun_path=”/var/run/nscd/socket” 百度

与dns解析有关。

由此可了解,命令行除了设置 –connect-timeout以外还需要对–dns-timeout进行设置,由此可以解决超时问题。此时所有的可能超时的步骤,均通过命令行得到控制。

当前的命令如下:

wget -P --dns-timeout=2s --connect-timeout=2s  /tmp/ http://example.com/myfile

当不断重复执行该命令,如果http://example.com/myfile是有效地址,则会不断生成/tmp/myfile,/tmp/myfile.1,/tmp/myfile.2…… 这样的话,但我需要文件名时,我只能获取最早生成的文件,如果最早生成的文件,因为网络中断等各种原因,导致文件损坏,或者不是我想要的,我在后续的操作中永远无法获取最新的文件。

因此需要指定文件名称:

wget -O --dns-timeout=2s --connect-timeout=2s  /tmp/myfile http://example.com/myfile

当前根据此设计的最佳方案:

wget --timeout=2s --spider remote-url  --如果成功下一步,否则退出且返回异常状态码
wget --connect-timeout=2s -O local_path/filename remote-url/filename