wget在进行https下载时超时不生效问题
来源:互联网 发布:免费的代理服务器软件 编辑:程序博客网 时间:2024/06/18 03:41
wget在进行https下载时超时不生效问题
wget是一个命令行的下载工具,可以通过–timeout设置超时时间(设置–timeout后,会同步设置三个超时值,–dns-timeout, –connect-timeout, –read-timeout),通过-t 设置重试次数(默认重试20次)。
问题在于它似乎不生效,我通过https协议下载一个文件,然后中途把网线拔掉,wget就一直卡住,不再退出。wget版本为1.11.4.
调试
使用strace调试了一下,发现在https下载时的系统调用如下(截取部分):
1.write(2, " ", 1) = 12.write(2, ".", 1) = 13.write(2, ".", 1) = 14.write(2, ".", 1) = 15.write(2, ".", 1) = 16.select(4, [3], NULL, NULL, {5, 0}) = 1 (in [3], left {4, 999971})7.read(3, "\27\3\1@ ", 5) = 58.read(3, "\215\302o\201\231\250\347\242WqY\336\247\200\327S\336\206i\363\10\262\345\255\230\231 G;?;\312"..., 16416) = 148019.read(3, 10.
select那里设置的5秒超时,这和我命令行设置的超时时间吻合。select返回然后开始读数据,读到第三次时卡住无响应了,是的,这时我拔掉了网线。
然后如法炮制,我测试了http下载时的情况,然而每次http下载时,我拔网线的时候都是停在select调用上,这样自然能超时。这是巧合吗?如下是部分系统调用栈:
1.select(4, [3], NULL, NULL, {0, 950000}) = 1 (in [3], left {0, 791529})2.read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 16384) = 28723.clock_gettime(CLOCK_MONOTONIC, {9281, 681190937}) = 04.write(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 2872) = 28725.select(4, [3], NULL, NULL, {0, 950000}) = 1 (in [3], left {0, 787252})6.read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 16384) = 43087.clock_gettime(CLOCK_MONOTONIC, {9281, 846431731}) = 0
发现一个问题没有,select唤醒之后,为什么http下载时只read一次,而https下载时read多次呢?
代码层面的问题
加载wget的源码搜了下,从sock读数据的部分大致整理如下:
1.int fd_read (int fd, char *buf, int bufsize, double timeout)2.{3. struct transport_info *info;4. LAZY_RETRIEVE_INFO (info);5. if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))6. return -1;7. if (info && info->imp->reader)8. return info->imp->reader (fd, buf, bufsize, info->ctx);9. else10. return sock_read (fd, buf, bufsize);11.}12.13.static int sock_read (int fd, char *buf, int bufsize)14.{15. int res;16. do17. res = read (fd, buf, bufsize);18. while (res == -1 && errno == EINTR);19. return res;20.}21.22.static int openssl_read (int fd, char *buf, int bufsize, void *arg)23.{24. int ret;25. struct openssl_transport_context *ctx = arg;26. SSL *conn = ctx->conn;27. do28. ret = SSL_read (conn, buf, bufsize);29. while (ret == -130. && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL31. && errno == EINTR);32. return ret;33.}
poll_internal
层层封装后,最后调用select来等待socket数据到来(是的,读超时的实现是使用select实现,不是通过setsockopt实现),select苏醒来了数据之后开始读数据。注意一下info->imp
,当http协议时它为空走普通sock_read
,当https协议时,它有注册自己的实现,会真真调用openssl_read
函数。该函数如上面看到的那样,调用SSL_read
读数据。
SSL_read
比较特殊,基于SSL/TSL记录来读,只有至少读到一条记录大小的数据后才能进行处理(检查完整性和解密)。由于SSL/TSL记录的大小可能超过底层传输的最大数据包大小,因此在SSL_read
返回前,可能要读取多个数据包。所以在strace时看到一次select后read了多次,然而网线已经拔掉,不可能read到数据,所以SSL_read
会一直卡住。
1.14.2版本实现
测了下本地ubuntu上的wget,可以超时,版本为1.14.2,下载了源码,看到SSL读操作的封装如下:
1.static int openssl_read (int fd, char *buf, int bufsize, void *arg)2.{3. struct openssl_read_args args;4. args.fd = fd;5. args.buf = buf;6. args.bufsize = bufsize;7. args.ctx = (struct openssl_transport_context*) arg;8.9. if (run_with_timeout(opt.read_timeout, openssl_read_callback, &args)) {10. return -1;11. }12. return args.retval;13.}
使用了run_with_timeout
函数来实现SSL_read
读超时(超时的实现原理为:闹钟信号+siglongjump)。strace的打印如下:
1.select(4, [3], NULL, NULL, {5, 0}) = 1 (in [3], left {4, 999997})2.rt_sigaction(SIGALRM, {0x800e3420, [ALRM], SA_RESTART}, {SIG_DFL, [ALRM], SA_RESTART}, 8) = 03.rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 04.setitimer(ITIMER_REAL, {it_interval={0, 0}, it_value={5, 0}}, NULL) = 05.read(3, "\27\3\3@\30", 5) = 56.read(3, "tV\22\"\335\201\327!\207\355\377<\16\314\320\24\322\370\rNh\351\4k\262,\211\221\310\207{\200"..., 16408) = 46197.read(3, 0x81b73c63, 11789) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)8.--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---9.rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 010.
- wget在进行https下载时超时不生效问题
- curl wget 不验证证书进行https请求
- wget下载https链接
- wget下载https链接
- 解决httpclient超时设置不生效的问题
- 在Git中 .gitignore不生效问题
- 使用springMVC + Spring进行web开发时,aop不生效的问题
- 解决Wget下载时的乱码问题
- wget FTP下载问题
- inotify不生效问题
- gitignore 不生效问题
- inotify不生效问题
- setLayoutParams()不生效问题
- .gitignore不生效问题
- 解决在用wget命令下载时出现“the host is unknow”的问题
- sencha touch在ios下使用Menu时内部html的onclick不生效的问题
- 一个奇怪的SQL问题:case when 在记录不存在时不生效
- css在JSP中不生效之路径问题
- TypeScript类型系统和基础类型
- JDBC的典型用法
- textarea 存入数据库后 换行 、空格显示
- 单例模式
- [数据预处理]one-hot编码
- wget在进行https下载时超时不生效问题
- SpringMVC原理与SpringMVC常用注解
- 把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。
- 20170705
- cocos2d-x-lua 单点触摸事件
- face 5k far landmark164 result
- 同源策略和跨域实现
- 【Linux基础】进程间调度
- 焓差法 空调制冷量 计算方法