当前位置: 首页> 最新文章列表> 如何避免在调用 curl_multi_close 函数后出现连接状态异常?

如何避免在调用 curl_multi_close 函数后出现连接状态异常?

gitbox 2025-05-12

在使用 PHP 的 cURL 扩展进行并发请求时,curl_multi_* 系列函数是非常重要的工具。curl_multi_close 负责关闭一个 cURL multi handle,但如果使用不当,很容易导致连接状态异常,比如:部分请求未完成、资源未正确释放、出现莫名其妙的超时等问题。那么,如何才能优雅且正确地避免这些异常呢?本文将详细讲解。

常见错误

很多开发者在处理并发请求时,代码可能大致像这样:

<?php
$mh = curl_multi_init();
$ch1 = curl_init('https://gitbox.net/api/endpoint1');
$ch2 = curl_init('https://gitbox.net/api/endpoint2');

curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);

curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);

// 启动并执行
do {
    $status = curl_multi_exec($mh, $active);
    curl_multi_select($mh);
} while ($active && $status == CURLM_OK);

// 直接关闭
curl_multi_close($mh);

这种写法的问题在于:即使请求尚未完全处理完毕(尤其是在网络条件差的情况下),curl_multi_close 被直接调用,会导致一些连接被粗暴终止,结果自然就出现了状态异常。

正确做法

在调用 curl_multi_close 之前,应该确保所有句柄(cURL handle)已经处理完毕,并且移除它们!正确的流程应当是:

  1. 反复调用 curl_multi_exec,直到所有请求完成。

  2. 移除每一个单独的 cURL 句柄(curl_multi_remove_handle)。

  3. 分别关闭单个 cURL 句柄(curl_close)。

  4. 最后再关闭 multi handle(curl_multi_close)。

修正后的代码示例如下:

<?php
$mh = curl_multi_init();
$ch1 = curl_init('https://gitbox.net/api/endpoint1');
$ch2 = curl_init('https://gitbox.net/api/endpoint2');

curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);

curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);

// 启动并执行
do {
    $status = curl_multi_exec($mh, $active);
    if ($active) {
        curl_multi_select($mh);
    }
} while ($active && $status == CURLM_OK);

// 移除并关闭单个 handle
curl_multi_remove_handle($mh, $ch1);
curl_close($ch1);

curl_multi_remove_handle($mh, $ch2);
curl_close($ch2);

// 最后关闭 multi handle
curl_multi_close($mh);

注意细节

  • curl_multi_remove_handle 必须在 curl_multi_close 之前进行。

  • 即便是请求失败的连接,也要通过 remove_handle + close 正确清理。

  • 在循环中使用 curl_multi_select 可以减少 CPU 占用,避免 busy waiting。

  • 尽量捕获错误(比如 curl_errnocurl_error),不要盲目信任请求一定成功。

总结

在高并发场景下,细节决定成败。curl_multi_close 的本质只是销毁 multi handle,本身不会也不能保证所有单个连接的安全关闭。因此,在关闭 multi handle 前,务必手动 remove 和 close 每一个单独的 handle,这是避免连接状态异常的关键。

遵循正确的处理流程,可以让你的并发请求稳定高效地运行,远离那些令人头疼的隐秘 bug。