Curl的毫秒超时的一个”Bug”

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了
时间: 2024-10-11 06:39:53

Curl的毫秒超时的一个”Bug”的相关文章

curl毫秒超时使用的坑

升级后的libcurl已经支持了毫米级别的超时.但是使用的时候还有一个坑需要注意跨过去 . libcurl如果检查到设置的timeout < 1s 那么会直接发出一个信号说 "已经超时了" 如果要使用毫秒超时 那么还需要关闭这个signal功能,即设置中需要多一个 curl_setopt($ch, CURLOPT_NOSIGNAL, 1); 但是,这样域名解析就不会受超时控制.也就是说,有可能被域名解析卡住很长时间,使用时需要注意. 然后curl_setopt($ch, CURL

Ibatis2.3.4的一个bug

java.lang.ClassCastException: com.chat.upgrade.domain.ClientFile cannot be cast to java.lang.String 今天查一个对象转化成json串报错的问题,查了两个小时,最后问题的根源居然是ibatis. ibatis的语句如下: <typeAlias alias="Client" type="com.chat.upgrade.domain.ClientFile"/>

Win10系统菜单打不开问题的解决,难道是Win10的一个Bug ?

Win10左下角菜单打不开,好痛苦,点击右下角的时间也没反应,各种不爽,折磨了我好几天,重装又不忍心,实在费劲,一堆开发环境要安装,上网找了很多方法都不适用.今天偶然解决了,仔细想了下,难道是Win10的一个Bug? 1.问题和现象 右下角菜单点不开,下面的状态栏的右键也没有反应.时间日期也点不开,音频喇叭同样点不开....各种烦人,百度一堆都无果.... 说明:Win10是正式版,已激活:杀毒也全盘扫描过,因为电脑是开发和办公用,几乎不上其他网站,所以中毒的可能性几乎为0. 2.解决方法 晚上

Universal-Image-Loader的一个BUG

使用UIL的内置圆角图片的功能时,发现一个BUG,就是它会拉伸图片,造成图片失真.费了一下午的功夫,重写了RoundedBitmapDisplayer,总算解决这个问题. 代码如下: public class RoundedBitmapDisplayer implements BitmapDisplayer { protected final int cornerRadius; protected final int margin; public RoundedBitmapDisplayer(i

ubuntu12.04 software-center 的一个BUG

ubuntu software-center 软件中心今天突然发现打不开了,就是在启动的过程中启动一半就退出了,多次启动无果.首先想到的办法当然是最彻底的两句话 sudo apt-get purge software-center sudo apt-get install software-center 结果未果,启动起来还是首先一个窗体初始化 接着..就直接关闭了.然后查看它的输出信息,发现原来是py输出中文导致的,因为我们窗体上有很多中文字体的组件需要加载,而python处理的时候有一个使用

docker 1.0.0发布以及一个bug依赖apparmor_parser

6月10号docker 1.0稳定版本发布,找了台ubuntu的机器,装了下 ubuntu version:12.04 docker version:1.0.0 装docker的步骤可以看官方文档:https://docs.docker.com/installation/ubuntulinux/ 装好之后,运行docker -d尝试启动docker守护进程,报错如下: [0fcb4ed6] +job serveapi(tcp://127.0.0.1:2375) [0fcb4ed6] +job i

【Qt】无边框窗体中带有ActiveX组件时的一个BUG

无意中发现的一个BUG,Qt5.1.1正式版首先创建一个GUI工程,拖入一个QAxWidget控件(为了使ActiveX生效,需要在.pro文件中加入CONFIG += qaxcontainer)接着,为了让ActiveX有效,需要引入一个组件,我这里引入的是IE组件 [cpp] view plain copy MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->s

使用getDrawable时遇到的一个bug

做一个筛选菜单时候,用到了dongjunkun的DropDownMenu,github地址:https://github.com/dongjunkun/DropDownMenu 遇到几个问题: (1)最右面的上三角形.下三角形很难看,需要改成向上箭头向下箭头,而且靠近文件,在右边: (2)背景颜色需要改成白色: (3)下面的子菜单的文字在最左边,需要居中: (4)第一次进来Fragment的时候DropDownMenu的下拉选项没有选中任意一项 上面几个需求看起来很容易改,不就是改改布局什么的,

memory_limit的一个bug | 风雪之隅

原文:memory_limit的一个bug | 风雪之隅 27 Nov 09 memory_limit的一个bug 作者: Laruence( ) 本文地址: http://www.laruence.com/2009/11/27/1164.html 转载请注明出处 PHP 5.2x中, 由于错误的选用了zend_atoi, 导致memory_limit不能设置为超过4G的值. 今天同事分享给我一个问题(thans to yanmi), 一段代码(PHP 5.2.11 Linux/X86_64),