當前位置: 首頁> 最新文章列表> 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。