Curl的毫秒超时的一个”Bug”
BUG 一个 超时 CURL 毫秒
2023-09-14 09:01:20 时间
Curl的毫秒超时的一个”Bug” 2015-12-15 PHP老杨 最近我们的服务在升级php使用的libcurl, 期望新版本的libcurl支持毫秒级的超时, 从而可以更加精细的控制后端的接口超时, 从而提高整体响应时间. 但是, 我们却发现, 在我们的CentOS服务器上, 当你设置了小于1000ms的超时以后, curl不会发起任何请求, 而直接返回超时错误(Timeout reached 28). 原来, 这里面有一个坑, CURL默认的, 在Linux系统上, 如果使用了系统标准的DNS解析, 则会使用SIGALARM来提供控制域名解析超时的功能, 但是SIGALARM不支持小于1s的超时, 于是在libcurl 7.28.1的代码中(注意中文注释行): int Curl_resolv_timeout(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **entry, long timeoutms) { ....... ....... #ifdef USE_ALARM_TIMEOUT if(data->set.no_signal) /* Ignore the timeout when signals are disabled */ timeout = 0; else timeout = timeoutms; if(!timeout) /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ return Curl_resolv(conn, hostname, port, entry); if(timeout < 1000) //如果小于1000, 直接超时返回 /* The alarm() function only provides integer second resolution, so if we want to wait less than one second we must bail out already now. */ return CURLRESOLV_TIMEDOUT; .... .... 可见, 当你的超时时间小于1000ms的时候, name解析会直接返回CURLRESOLV_TIMEOUT, 最后会导致CURLE_OPERATION_TIMEDOUT, 然后就Error, Timeout reached了… 这….太坑爹了吧? 难道说, 我们就不能使用毫秒超时么? 那你提供这功能干啥? 还是看代码, 还是刚才那段代码, 注意这个(中文注释行): #ifdef USE_ALARM_TIMEOUT if(data->set.no_signal) //注意这行 /* Ignore the timeout when signals are disabled */ timeout = 0; else timeout = timeoutms; if(!timeout) /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ return Curl_resolv(conn, hostname, port, entry); if(timeout < 1000) /* The alarm() function only provides integer second resolution, so if we want to wait less than one second we must bail out already now. */ return CURLRESOLV_TIMEDOUT; 看起来, 只要set.no_signal 这个东西为1, 就可以绕过了… 那这个玩意是啥呢? 这就简单了, grep一下代码, 发现: case CURLOPT_NOSIGNAL: /* * The application asks not to set any signal() or alarm() handlers, * even when using a timeout. */ data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE; break; 哈哈, 原来是这货: <?php curl_setopt($ch, CURLOPT_NOSIGNAL, 1); ?> 加上这个OPT以后, 一切终于正常了! 后记: 这样一来, 就会有一个隐患, 那就是DNS解析将不受超时限制了, 这在于公司内部来说, 一般没什么问题, 但是万一DNS服务器hang住了, 那就可能会造成应用超时. 那么还有其他办法么? 有, 那就是Mike提醒的, 我们可以让libcurl使用c-ares(C library for asynchronous DNS requests)来做名字解析. 具体的可以在config curl的时候: ./configure --enable-ares[=PATH] 这样就可以不用设置NOSIGNAL了
相关文章
- 使用 selenium 写的多进程全网页截图工具,发现了 PhantomJS 截图的 bug
- ESBuild压缩CSS引发的一个兼容性Bug的解决姿势
- 【Git必知必会】多人协同开发,紧急修复线上bug的操作指南。
- 5. 如何描述一个bug / 如何定义bug的类型级别 / bug的生命周期
- 真赔麻了!一个BUG赔10万,一个回帖又赔10万!
- 这bug你解决不了?
- 如何使用Arsenal快速部署功能强大的Bug Bounty工具
- 爆火的ChatGPT太强了!写代码、改bug,网友:可取代Stack Overflow了
- mobx 6 关于computed 不更新的bug
- 一个有趣的BUG
- 2022年底C# 解压zip文件遇到的一个Bug
- 并发编程Bug起源:可见性、有序性和原子性问题
- 记一个SwipeMenuListView侧滑删除错乱的Bug详解手机开发
- Oracle临时表BUG 遭遇不测崩溃惊魂(oracle临时表bug)
- Oracle Bug问题总结修复折中求取完美(oracle bug汇总)
- Oracle Bug查找新姿势终极突破(oracle bug查找)
- IE6下js通过css隐藏select的一个bug
- 关于c语言的一个小bug详解
- 解析Tomcat6、7在EL表达式解析时存在的一个Bug
- ShareSDK造成App崩溃的一个BUG原因分析以及Fix方法
- PHP函数strip_tags的一个bug浅析