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

来源:互联网 发布:java 字符串替换 编辑:程序博客网 时间:2024/06/06 12:56
  • 本文地址: http://www.laruence.com/2014/01/21/2939.html
  • 转载请注明出处

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

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

原来, 这里面有一个坑, CURL默认的, 在Linux系统上, 如果使用了系统标准的DNS解析,则会使用SIGALARM来提供控制域名解析超时的功能, 但是SIGALARM不支持小于1s的超时, 于是在libcurl7.28.1的代码中(注意中文注释行):

  1. int Curl_resolv_timeout(structconnectdata *conn,
  2.                         constchar *hostname,
  3.                         intport,
  4.                         structCurl_dns_entry **entry,
  5.                         longtimeoutms)
  6. {
  7. .......
  8. .......
  9. #ifdef USE_ALARM_TIMEOUT
  10.   if(data->set.no_signal)
  11.     
  12.     timeout= 0;
  13.   else
  14.     timeout= timeoutms;
  15.  
  16.   if(!timeout)
  17.     
  18.     returnCurl_resolv(conn,hostname,port,entry);
  19.  
  20.   if(timeout<</SPAN> 1000)//如果小于1000, 直接超时返回
  21.     
  22.     returnCURLRESOLV_TIMEDOUT;
  23.  
  24.   ....
  25.   ....

可见, 当你的超时时间小于1000ms的时候, name解析会直接返回CURLRESOLV_TIMEOUT,最后会导致CURLE_OPERATION_TIMEDOUT, 然后就Error, Timeout reached了…

这….太坑爹了吧? 难道说, 我们就不能使用毫秒超时么? 那你提供这功能干啥?

还是看代码, 还是刚才那段代码, 注意这个(中文注释行):

  1. #ifdef USE_ALARM_TIMEOUT
  2.   if(data->set.no_signal)//注意这行
  3.     
  4.     timeout= 0;
  5.   else
  6.     timeout= timeoutms;
  7.  
  8.   if(!timeout)
  9.     
  10.     returnCurl_resolv(conn,hostname,port,entry);
  11.  
  12.   if(timeout<</SPAN> 1000)
  13.     
  14.     returnCURLRESOLV_TIMEDOUT;

看起来, 只要set.no_signal 这个东西为1, 就可以绕过了… 那这个玩意是啥呢?

这就简单了, grep一下代码, 发现:

  1.  
  2.   caseCURLOPT_NOSIGNAL:
  3.     
  4.     data->set.no_signal= (0!= va_arg(param,long))?TRUE:FALSE;
  5.     break;

哈哈, 原来是这货:

0 0
原创粉丝点击