今天运行脚本遇到一个奇怪的问题,就是程序会卡在cURL请求的后期。无一例外,无一回应。和对方沟通后,我说,“哥们,你的程序是不是有问题?我这里查了查,说是12:30左右没有收到你的请求,然后我用在线的json工具请求它。通过。”是不是很尴尬,关键是不知道为什么。然后我一直尝试重新运行脚本,偶尔有一些脚本跑了,但好景不长,随时可能出现无效时间。一直看,一开始可以正常完成请求,随着时间的推移执行时间逐渐增加,然后就可能变成死连接。我突然想到,cURL发送的一些请求一定是没有响应而失效的。变成了僵尸连接,脚本一直被阻塞,导致资源一直存在,但是不能继续使用。找了各种资料,也想尝试写一个类似于定时器的定喜。如果脚本执行时间超过1分钟,cURL链接将被强制丢弃。不知道PHP是怎么实现这样的需求的,犹豫要不要用go来实现。涉及到json、xml等,毕竟用go不如php方便,于是就去说明书看了cURL的内容,想找点有用的。而且cURL命令行工具有重试功能,估计扩展也有。但是如何配置呢?看完本文关于超时的PHP超时处理综合总结,才明白是因为我的代码在设置cURL连接选项时只设置了连接超时,并没有设置执行超时。观察到数据应该在10秒内正常返回,我将超时和执行时间设置为30秒。增加这个参数限制后,我们终于可以捕捉到无响应的请求了,剩下的就是如何处理无法在指定时间内返回结果的资源了。只是这几个参数没看懂,排查问题浪费了整整一个下午。/***CURLOPT_TIMEOUT设置允许cURL执行的最大秒数。*CURLOPT_TIMEOUT_MS设置cURL允许执行的最大毫秒数。(在cURL7.16.2中添加。从PHP5.2.3开始可用。)*CURLOPT_CONNECTTIMEOUT启动连接之前等待的时间。如果设置为0,它将无限期等待。*CURLOPT_CONNECTTIMEOUT_MS等待连接尝试的时间,以毫秒为单位。如果设置为0,则无限等待。它是在cURL7.16.2中添加的。自PHP5.2.3起可用。*CURLOPT_DNS_CACHE_TIMEOUT设置在内存中保存DNS信息的时间,默认为120秒。*/增加执行超时后请求设置功能。/***curl请求**@param$url*@paramstring$postData*@paramint$timeout*@returnarray|mixed*@throwsException*/protectedstaticfunctionpost($url,$postData='',$timeout=5){$ret=array();$次=5;做{$ch=curl_init();curl_setopt($ch,CURLOPT_URL,$url);curl_setopt($ch,CURLOPT_CUSTOMREQUEST,"POST");curl_setopt($ch,CURLOPT_POST,true);curl_setopt($ch,CURLOPT_HEADER,false);如果($postData!=''){curl_setopt($ch,CURLOPT_POSTFIELDS,$postData);}curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);//重要的是,该处不能丢curl执行最大秒数curl_setopt($ch,CURLOPT_TIMEOUT,$timeout);$output=curl_exec($ch);如果($errNo=curl_errno($ch)){error_log(“错误[$errNo]:”。curl_error($ch));}else{$ret=json_decode($output,true);//解析的结果set为空时停止查询}取消设置($输出);}curl_close($ch);如果(isset($ret[0])&&$ret[0]){返回$ret;}}while($times--);exit(__METHOD__.":cURLrequestretry{$times}次后仍然没有响应,执行exit");}超时时的提示信息设置如下:error_log("Error[$errNo]:".curl_error($ch));我设置了连接时间和执行时间限制是30秒Error[28]:Operationtimedoutafter30000millisecondswith0bytesreceived可以输出查看。对于这个超时,直接丢弃连接,重新初始化资源请求。当然这里尝试重试6次,但是6次之后还是不能正常执行,只能想其他办法了。虽然不知道最后为什么会连接失败,但是经过这之后,可以保证基本可以完成任务了。我执行了一个月的运行脚本,超时了好多次。幸运的是,没有等到重试6次就请求成功了。从错误类型可以看出,确实有一些请求在30秒内无法执行。错误[28]:操作在30000毫秒后超时,收到0个字节错误[28]:操作在30000毫秒后超时,收到0个字节错误[28]:操作在30000毫秒后超时,收到323196个字节中的62399个
