You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker环境PHP运行UDP服务socket_sendto报Unknown host错误

问题:请告知调用socket_sendto函数时为何会触发Unknown host错误

运行环境
centos 7.9
php-fpm 7.4 AND php-fpm 8.1
部署于docker容器内
/etc/hosts配置
<docker net ip>     <docker container id>
127.0.0.1           nd.domain.com
启动方式
php -q SERVER.php
服务源码
#!/usr/local/bin/php -q
<?php

// error_reporting(E_ALL);
// set_time_limit(0);
// ob_implicit_flush();

$address = '0.0.0.0';
$port = 80;
echo "server now start\r\n";

$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP) or dir("create failed this socket");

if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
    echo 'Unable to set option on socket: '. socket_strerror(socket_last_error()) . PHP_EOL;
}


socket_bind($socket, $address, $port) or dir("Failed to bind to (".$address.":".$port.")");
echo "server binded\r\n";

$messageBuffer = "";

$clients = [];
while (true){

    if (@socket_recvfrom($socket, $messageBuffer, 2048, MSG_WAITALL, $ip, $port)) {
        $address = "$ip:$port";
        echo "Receive data : " . $messageBuffer . " FROM " . $address. "\r\n";

        if (!isset($clients[$address])) 
            $clients[$address] = array();
     
        $data = "hello-world";
        $client_ip = gethostbyname($address);
        echo "callback - send to " . $client_ip . "\r\n";
        if (@socket_sendto($socket, $data, strlen($data), 0, $client_ip, $port)) {
            echo "sendto ok";
        } else {
            echo socket_strerror(socket_last_error($socket))."\r\n";
        };
    } else {
        echo socket_strerror(socket_last_error($socket))."\r\n";
    };
}

socket_close($socket);
?>
服务运行日志

php-fpm 8.1(开启错误显示)环境日志

server now start
server binded
Receive data : hello world FROM 123.123.123.12:12345
callback - send to 123.123.123.12:12345

Warning: socket_sendto(): Host lookup failed [-10000]: Unknown error -10000 in [err-path] on line 47
Unknown error -10000

php-fpm 7.4(关闭错误显示)环境日志

Receive data : 0101010101! FROM 123.123.123.12:12345
callback - send to 123.123.123.12:12345
Unknown host

错误原因

触发错误的核心是代码逻辑有两处明显问题:

  • socket_recvfrom接收到数据时,会把客户端的IP和端口分别写入$ip、$port两个变量,这里的$port和开头定义监听端口的$port是全局同名变量,直接覆盖了原来的监听端口值,属于变量污染。
  • 你把客户端IP和端口拼接成了IP:端口格式的字符串(比如日志里的123.123.123.12:12345),再把这个拼接后的字符串传入gethostbyname()做域名解析。gethostbyname()只接受纯域名、纯IP格式的入参,传入带端口的拼接字符串会直接解析失败,返回原字符串。
  • 最后你把解析失败、带端口的字符串作为目标IP传入socket_sendto(),函数无法识别这种非法格式的目标地址,就会抛出Unknown host错误,PHP8.1环境下还会同步抛出主机查找失败的-10000警告。
修复方案
  1. 把socket_recvfrom写入的客户端IP、端口变量改名,和全局监听端口变量区分开,避免变量覆盖。
  2. 去掉多余的gethostbyname调用:socket_recvfrom返回的$ip本身就是可直接使用的纯客户端IP,不需要再做解析,更不能把带端口的拼接字符串传入解析函数。

修复后的核心代码段参考:

$listen_address = '0.0.0.0';
$listen_port = 80;
// ... 省略socket创建、绑定逻辑,绑定使用$listen_address、$listen_port
while (true){
    // 客户端地址变量单独命名,避免和监听配置冲突
    if (@socket_recvfrom($socket, $messageBuffer, 2048, MSG_WAITALL, $client_ip, $client_port)) {
        $client_addr = "$client_ip:$client_port";
        echo "Receive data : " . $messageBuffer . " FROM " . $client_addr. "\r\n";

        if (!isset($clients[$client_addr])) 
            $clients[$client_addr] = array();
     
        $data = "hello-world";
        echo "callback - send to " . $client_ip . ":" . $client_port . "\r\n";
        // 直接用拿到的纯客户端IP、端口发数据,不需要额外解析
        if (@socket_sendto($socket, $data, strlen($data), 0, $client_ip, $client_port)) {
            echo "sendto ok\r\n";
        } else {
            echo socket_strerror(socket_last_error($socket))."\r\n";
        };
    } else {
        echo socket_strerror(socket_last_error($socket))."\r\n";
    };
}

内容的提问来源于stack exchange,提问作者lIIlIllIIlllIIlI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 21:54:32