網路連線壅塞是一個難解的問題, 因為網路會產生抖動(Jitter)現象, 抖動發生時, 連線會突然變得很慢. 當狀況改善後就會回復. 但很大的原因是因為是因為 DNS 解析或是 TCP 交握的過程產生的問題.
當 curl
連線到一個 HTTP 網址時,其工作流程包括以下幾個主要步驟:
1. DNS 查詢
- 目標:解析主機名 (如
example.com
) 對應的 IP 位址。 - 過程:
curl
通過 DNS 伺服器進行查詢,獲取目標伺服器的 IP 地址。 - 結果:若查詢成功,返回 IP 地址,
curl
將繼續下一步。若查詢失敗,curl
則返回 DNS 錯誤並中止。
2. TCP 三向交握 (Three-Way Handshake)
- 目標:建立與目標伺服器的 TCP 連線。
- 過程:
curl
通過系統內核發送一個SYN
封包,目標伺服器回應SYN-ACK
,然後curl
返回ACK
完成三向交握,建立起 TCP 連線。 - 結果:若在
--connect-timeout
設定時間內未完成三向交握,則連線失敗並返回超時錯誤。
3. 發送 HTTP 請求
- 目標:向伺服器發送具體的 HTTP 請求,根據 URL 設定不同的請求方法(如
GET
、POST
)。 - 過程:
curl
構建 HTTP 請求標頭並附加任何所需的數據(如表單數據),然後通過已建立的 TCP 連線將請求發送到伺服器。 - 結果:伺服器接收請求並準備回應,若過程中出現網路問題,則請求可能中止或失敗。
4. 伺服器處理請求並返回回應
- 目標:伺服器根據請求的 URL 路徑處理並生成對應的回應內容。
- 過程:伺服器確認請求內容後,由 HTTP 伺服器(如
httpd
)根據需求(例如讀取靜態文件或調用後端服務)生成回應,並加上適當的 HTTP 狀態碼和標頭。 - 結果:伺服器將回應內容傳回給
curl
客戶端。
5. 接收 HTTP 回應
- 目標:
curl
從伺服器接收回應數據,並在終端或指定的輸出目標中顯示。 - 過程:
curl
讀取 HTTP 回應標頭(包括狀態碼,如200 OK
、404 Not Found
等)及內容,並根據需要顯示、保存或處理該回應。 - 結果:若指定了輸出文件,
curl
將回應寫入文件;若未指定,則在終端中顯示。若在接收期間出現中斷或錯誤,則可能返回部分內容或失敗。
6. TCP 連線關閉 (四次揮手)
- 目標:完成數據傳輸後,
curl
與伺服器結束連線。 - 過程:
curl
發送FIN
封包,伺服器回應ACK
,並發送自己的FIN
封包,最後curl
回應ACK
,四次揮手完成。 - 結果:TCP 連線釋放,
curl
任務完成。
curl
的 HTTP 工作流程可概括為:DNS 查詢 -> TCP 連線建立 -> 發送 HTTP 請求 -> 伺服器處理並回應 -> 接收回應 -> TCP 連線關閉。
在 HTTP 壅塞情況下 curl 參數,--connect-timeout
和 --max-time
的表現會有所不同,具體取決於壅塞發生的階段:
--connect-timeout
:--connect-timeout
主要針對連線的建立過程(TCP 三次握手)。如果壅塞導致連線過程延遲,例如因為服務器回應延遲或網路繁忙而無法快速建立連線,這個參數會限制等待的時間。- 在連線成功建立後,
--connect-timeout
就不再生效,因此這個參數並不會影響數據傳輸階段的壅塞情況。 - 情境:假如壅塞發生在連線建立之前,
curl
會在達到--connect-timeout
設定的秒數後中止嘗試。
--max-time
:--max-time
影響整個請求的持續時間,因此即使成功建立連線,但在傳輸數據時因壅塞而變慢,--max-time
仍會在達到設定的上限時間後中止請求。- 這個參數可以在連線建立和數據傳輸的任一階段發揮作用,是更全面的時間限制。
- 情境:如果壅塞發生在連線建立之後,
curl
在達到--max-time
設定的秒數後會中止整個請求。
使用 --connect-timeout
和 --max-time
選項來測試壅塞情境。
- bash 指令:
- 說明:
--connect-timeout 5
設置了連線超時為 5 秒,--max-time 10
設置整個請求的最大等待時間為 10 秒。 - 效果:如果伺服器在 5 秒內無法建立連線,或者請求超過 10 秒未完成,
curl
會中止並返回超時錯誤。
在 PHP 中,我們可以利用 CURLOPT_CONNECTTIMEOUT
和 CURLOPT_TIMEOUT
這兩個 cURL
選項來控制 HTTP 請求的超時行為,以便提早識別出 HTTP 壅塞的情況。這兩個參數的作用和 curl
指令行工具中的 --connect-timeout
和 --max-time
類似:
$ch = curl_init();
// 設置要請求的 URL
curl_setopt($ch, CURLOPT_URL, "http://example.com");
// 設置連線超時為 5 秒,判斷連線建立過程中是否有壅塞
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
// 設置整個請求超時為 10 秒,應對數據傳輸階段的壅塞
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
// 設置返回結果而不是直接輸出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 執行請求並取得回應
$response = curl_exec($ch);
// 檢查是否有錯誤
if (curl_errno($ch)) {
echo "Error: " . curl_error($ch);
} else {
echo "Response: " . $response;
}
// 關閉 cURL 資源
curl_close($ch);