转载

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

最近我们的服务在升级php使用的libcurl, 期望新版本的libcurl支持毫秒级的超时, 从而可以更加精细的控制后端的接口超时, 从而提高整体响应时间.

但是, 我们却发现, 在我们的CentOS服务器上, 当你设置了小于1000ms的超时以后, curl不会发起任何请求, 而直接返回超时错误(Timeout reached 28).

原来, 这里面有一个坑,  CURL默认的, 在Linux系统上, 使用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以后, 一切终于正常了!

最后, 这个我想是Curl的一个bug吧, 只不过我们没想明白他们为啥不用setitimer…

参考:  http://stackoverflow.com/questions/7987584/curl-timeout-less-than-1000ms-always-fails

原文  http://blogread.cn/it/article/6998?f=hot1
正文到此结束
Loading...