当前位置: 首页> 最新文章列表> 使用 strace 或 netstat 排查 socket_accept() 监听状态问题

使用 strace 或 netstat 排查 socket_accept() 监听状态问题

M66 2025-06-03

在使用 PHP 编写基于 Socket 的服务器应用时,socket_accept() 是接收客户端连接的关键函数。然而在某些场景中,即便程序逻辑正确,也可能遇到 socket_accept() 无法正常接收连接的情况。本文将介绍如何使用 stracenetstat 工具,快速定位和解决这一问题。

一、前提:一个典型的 PHP Socket 服务端示例

以下是一个简单的 PHP 服务端程序,监听 8080 端口:

<?php
$host = '0.0.0.0';
$port = 8080;

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, $host, $port);
socket_listen($socket);

echo "Server listening on $host:$port\n";

while (true) {
    $client = socket_accept($socket);
    if ($client === false) {
        echo "Failed to accept connection\n";
        continue;
    }

    $msg = "Hello from server\n";
    socket_write($client, $msg, strlen($msg));
    socket_close($client);
}
?>

当你发现 socket_accept() 卡住,或者始终返回 false 时,就需要借助系统工具来深入排查。

二、使用 strace 跟踪系统调用

strace 是一个 Linux 下的系统调用追踪工具,可以直接查看 PHP 脚本在运行时调用了哪些系统底层函数,以及它们的执行结果。

步骤:

  1. 找到正在运行的 PHP 进程 PID,例如使用 ps

    ps aux | grep php
    
  2. 使用 strace 附加到该进程:

    strace -p <PID> -e trace=network
    
  3. 观察输出中是否存在如下行为:

    • accept(...) = -1:系统调用失败,通常伴随错误码(如 EAGAINECONNABORTED 等)

    • listen(...)bind(...) 报错:可能意味着端口被占用或权限不足

    • 没有调用 accept():程序可能卡在其他地方

如果 strace 显示 accept() 正常,但仍然无连接接入,那么问题可能出在网络层或防火墙。

三、使用 netstat 或 ss 确认监听状态

netstatss 可用于检查端口是否处于监听状态,以及是否已有连接建立。

检查监听状态:

netstat -tlnp | grep :8080

或:

ss -tlnp | grep :8080

你应该能看到类似以下的输出:

tcp    LISTEN     0      128    0.0.0.0:8080    0.0.0.0:*     users:(("php",pid=12345,fd=3))
  • 如果没有任何监听,说明 socket_bind()socket_listen() 失败;

  • 如果监听正常但无连接,可能是客户端未发起连接,或被防火墙拦截;

  • 如果状态为 CLOSE_WAITTIME_WAIT,说明连接生命周期异常结束。

四、进一步调试建议

  1. 检查错误信息
    每次 Socket 调用后使用 socket_strerror(socket_last_error()) 查看具体错误信息。

  2. 防火墙或 SELinux 限制
    使用 iptablesfirewalld 确认 8080 端口未被阻塞。

  3. 端口被其他程序占用
    使用 lsof -i :8080 检查是否有其他程序占用了该端口。