在使用 PHP 进行网络请求时,我们常用到 cURL 库。cURL 是一个强大的工具,它不仅支持简单的 HTTP 请求,还支持如 cookie、DNS、SSL 等高级特性。
其中,curl_share_init 是一个比较少为人知的 cURL 特性,它允许多个 cURL 句柄共享数据,比如 DNS 缓存、cookie、SSL session 等。通过共享 DNS 缓存,我们可以减少重复的域名解析,提高性能。
但在实际使用中,很多人会疑问:
共享的 DNS 缓存到底有没有生效?要如何监控?
本文就带你一步步分析,并给出完整的 PHP 示例。
curl_share_init() 函数用于初始化一个共享句柄,配合 curl_setopt 的 CURLOPT_SHARE 选项,可以让多个 cURL 请求共享某些数据。常见共享的内容包括:
DNS 缓存(CURL_LOCK_DATA_DNS)
Cookie(CURL_LOCK_DATA_COOKIE)
SSL 会话(CURL_LOCK_DATA_SSL_SESSION)
例如:
$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
这样多个 cURL 句柄绑定同一个 $sh,就能共享 DNS 缓存。
虽然 cURL 没有直接提供“监控 DNS 缓存命中”的接口,但我们可以间接观察:
首次请求耗时:首次请求通常包含 DNS 解析时间。
后续请求耗时:如果启用了共享 DNS,后续相同域名的请求应明显减少解析时间。
换句话说,我们可以用 CURLINFO_NAMELOOKUP_TIME 和 CURLINFO_TOTAL_TIME 两个 cURL 选项,分别监控:
域名解析时间
总耗时
通过比较首个请求与后续请求的 NAMELOOKUP_TIME,就能判断 DNS 缓存是否生效。
以下是一个使用 curl_share_init 的完整 PHP 代码,向 https://m66.net/test 发送两次请求,并打印 DNS 解析时间:
<?php
$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
$url = 'https://m66.net/test';
// 第一次请求
$ch1 = curl_init($url);
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch1, CURLOPT_SHARE, $sh);
curl_exec($ch1);
$dns_time1 = curl_getinfo($ch1, CURLINFO_NAMELOOKUP_TIME);
$total_time1 = curl_getinfo($ch1, CURLINFO_TOTAL_TIME);
curl_close($ch1);
echo "第一次请求:\n";
echo "DNS 解析时间: {$dns_time1} 秒\n";
echo "总耗时: {$total_time1} 秒\n";
// 等待1秒,模拟新的请求
sleep(1);
// 第二次请求
$ch2 = curl_init($url);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_SHARE, $sh);
curl_exec($ch2);
$dns_time2 = curl_getinfo($ch2, CURLINFO_NAMELOOKUP_TIME);
$total_time2 = curl_getinfo($ch2, CURLINFO_TOTAL_TIME);
curl_close($ch2);
echo "\n第二次请求:\n";
echo "DNS 解析时间: {$dns_time2} 秒\n";
echo "总耗时: {$total_time2} 秒\n";
// 清理
curl_share_close($sh);
?>
? 启用共享:用 curl_share_init 和 CURLSHOPT_SHARE 配置共享 DNS 数据。
? 获取时间:通过 curl_getinfo 拿到 CURLINFO_NAMELOOKUP_TIME。
? 对比效果:第一次请求通常会有明显的 DNS 耗时(比如几十毫秒);第二次如果缓存生效,NAMELOOKUP_TIME 会接近 0。
同一域名:只有相同的主机名(例如 m66.net)才能命中缓存。
PHP cURL 版本:部分老版本 PHP 可能不完全支持 curl_share。建议用 phpinfo() 检查 cURL 版本。
线程安全:如果在多线程或多进程环境下使用 curl_share,需要确保加锁安全。