如何在PHP中快速获取本地服务器的公网IP?
快速获取服务器公网IP的可行方案
核心结论
本地直接获取路由器后方服务器的公网IP没有通用方案(除非你的路由器提供API接口,或者服务器本身有绑定公网的网卡),但通过优化远程请求+缓存策略,完全可以把耗时稳定控制在35ms以内,甚至更低。
一、极致优化的远程请求方案
1. 搭建专属的极简IP查询服务
第三方公共IP服务慢的核心原因是:跨网络传输、冗余内容(JSON/HTML)、服务负载高。最快的方式是在同机房/同区域的另一台服务器上搭一个仅返回纯IP字符串的接口:
// 同机房服务器上的ip.php <?php echo $_SERVER['REMOTE_ADDR']; exit; ?>
这个接口没有任何多余内容,传输数据量仅几字节,能大幅降低传输耗时。
2. 极致优化CURL参数
针对上述专属接口,用以下参数配置CURL,把请求开销压到最低:
function get_public_ip() { $ch = curl_init('http://同机房服务器IP/ip.php'); // 核心优化参数 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 30); // 连接超时30ms curl_setopt($ch, CURLOPT_TIMEOUT_MS, 100); // 总超时100ms curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // 禁止重定向 curl_setopt($ch, CURLOPT_NOSIGNAL, true); // Linux下避免信号干扰 curl_setopt($ch, CURLOPT_TCP_NODELAY, true); // 禁用Nagle算法,减少延迟 curl_setopt($ch, CURLOPT_FORBID_REUSE, false); // 允许复用TCP连接 curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); // 优先用HTTP/1.1 // 若服务器支持HTTP/2,可改用CURL_HTTP_VERSION_2_0进一步提速 $ip = curl_exec($ch); curl_close($ch); return trim($ip); }
同机房的TCP请求延迟通常在10-20ms左右,加上请求处理时间,完全能满足35ms以内的要求。
3. 缓存策略(关键)
公网IP不会频繁变动,把获取到的IP缓存到本地文件或内存缓存(比如Redis),比如缓存1小时:
function get_cached_public_ip() { $cache_file = '/tmp/server_ip.cache'; $cache_ttl = 3600; // 1小时缓存 // 检查缓存是否有效 if (file_exists($cache_file) && time() - filemtime($cache_file) < $cache_ttl) { return file_get_contents($cache_file); } // 缓存失效,重新获取 $ip = get_public_ip(); if ($ip) { file_put_contents($cache_file, $ip); } return $ip; }
缓存生效时,读取耗时仅几毫秒,完全达标。
二、更快的UDP请求方案
UDP不需要TCP的三次握手,延迟比TCP更低,适合追求极致速度的场景。
1. 搭建UDP IP服务(同机房)
// UDP服务器端(运行在同机房服务器) $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); socket_bind($socket, '0.0.0.0', 12345); while (true) { // 接收客户端请求(无需处理内容) socket_recvfrom($socket, $data, 1024, 0, $client_ip, $client_port); // 直接返回客户端IP socket_sendto($socket, $client_ip, strlen($client_ip), 0, $client_ip, $client_port); }
2. 客户端请求代码
function get_public_ip_udp() { $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec' => 0, 'usec' => 50000]); // 50ms超时 // 发送空请求 socket_sendto($socket, '', 0, 0, '同机房UDP服务器IP', 12345); // 接收返回的IP $result = socket_recvfrom($socket, $ip, 15, 0, $server_ip, $server_port); socket_close($socket); return $result ? trim($ip) : false; }
同机房的UDP请求延迟通常在5-15ms,加上缓存,能轻松满足你的速度要求。
三、关于模拟浏览器iframe的思路
浏览器加载iframe快是因为浏览器自带连接池、缓存机制,且是异步加载,但在PHP端模拟这个逻辑本质还是HTTP请求,优化后和上述CURL方案效果一致,没有额外优势。
内容的提问来源于stack exchange,提问作者Daniel Bengtsson
相关产品推荐
相关产品推荐

