當前位置: 首頁> 最新文章列表> 使用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. 檢查錯誤信息<br> 每次Socket 調用後使用socket_strerror(socket_last_error())查看具體錯誤信息

  2. 防火牆或SELinux 限制<br> 使用iptables或firewalld確認8080 端口未被阻塞

  3. 端口被其他程序佔用<br> 使用lsof -i :8080檢查是否有其他程序佔用了該端口