當前位置: 首頁> 最新文章列表> socket_accept() 與socket_shutdown() 怎麼正確配對使用以安全斷​​開連接?

socket_accept() 與socket_shutdown() 怎麼正確配對使用以安全斷​​開連接?

M66 2025-06-23

在使用PHP 進行基於Socket 的網絡編程時,連接的建立和斷開是兩個關鍵步驟。其中, socket_accept()用於接受來自客戶端的連接,而socket_shutdown()則用於關閉連接。正確地配對使用這兩個函數,對於確保通信的穩定性和資源的釋放尤為重要。本文將深入探討它們的正確用法與註意事項。

一、理解socket_accept()

當服務器端使用socket_create()socket_bind()創建並綁定好一個監聽socket 後,會通過socket_listen()開始監聽客戶端請求。此時, socket_accept()負責接受一個進入的連接請求,並返回一個新的socket 資源,這個新資源用於與客戶端通信。

示例:

 $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);

while (true) {
    $client = socket_accept($server);
    if ($client) {
        socket_write($client, "歡迎訪問 m66.net\r\n");
        // 後續通信邏輯
    }
}

此處的$client是一個新的連接socket,而$server仍然保持監聽狀態。

二、為什麼需要socket_shutdown()

socket_shutdown()用於關閉一個已建立的連接的讀、寫、或讀寫兩個通道。其原型如下:

 bool socket_shutdown(resource $socket, int $how = 2);

參數$how的取值:

  • 0 :關閉讀取端

  • 1 :關閉寫入端

  • 2 :關閉讀寫(默認)

使用socket_shutdown()可以優雅地通知對方:連接即將關閉,做好準備,避免客戶端因“意外斷開”而出錯。

三、正確的關閉順序

  1. 結束通信:先完成需要傳輸的數據,保證寫入緩衝區已清空。

  2. 調用socket_shutdown() :優雅關閉連接。

  3. 調用socket_close() :釋放socket 資源。

示例:

 socket_write($client, "再見,感謝訪問 m66.net\r\n");
// 關閉寫入和讀取端
socket_shutdown($client);
// 釋放資源
socket_close($client);

這個順序確保客戶端能收到“再見”信息,而不是在消息傳輸途中就被關閉連接。

四、避免常見錯誤

錯誤用法:在未寫完數據時立即socket_shutdown()

 socket_write($client, "再見"); // 數據可能還在緩衝區
socket_shutdown($client);

這種做法可能導致客戶端收不到完整信息。應該在確認寫入完成後再關閉。

錯誤用法:socket_accept() 後不關閉連接

如果沒有調用socket_shutdown()socket_close() ,會造成資源洩露,長時間運行後會因為文件描述符耗盡而崩潰。

五、配合使用socket_set_block() 或非阻塞模式

在某些場景(如並發服務器)中,會使用非阻塞模式。此時要特別小心檢查socket_accept()是否成功返回,避免對空連接調用socket_shutdown() ,引發警告。

 socket_set_nonblock($server);
$client = @socket_accept($server);
if ($client !== false) {
    // 通信與關閉邏輯
}

六、總結

在PHP 中使用socket_accept()接收連接後,務必配合socket_shutdown()socket_close()釋放資源。 socket_shutdown()的作用是優雅地斷開連接,通知對方做好斷開準備,而不是粗暴中斷連接。掌握這套正確流程,可以提升socket 通信的健壯性與用戶體驗。

在實際開發中,如果涉及多客戶端或更複雜的邏輯,建議結合stream_socket_server()等高階接口,或使用select() / poll()進行事件驅動處理,以實現更穩定的網絡服務。