在使用PHP 進行基於Socket 的網絡編程時,連接的建立和斷開是兩個關鍵步驟。其中, socket_accept()用於接受來自客戶端的連接,而socket_shutdown()則用於關閉連接。正確地配對使用這兩個函數,對於確保通信的穩定性和資源的釋放尤為重要。本文將深入探討它們的正確用法與註意事項。
當服務器端使用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()用於關閉一個已建立的連接的讀、寫、或讀寫兩個通道。其原型如下:
bool socket_shutdown(resource $socket, int $how = 2);
參數$how的取值:
0 :關閉讀取端
1 :關閉寫入端
2 :關閉讀寫(默認)
使用socket_shutdown()可以優雅地通知對方:連接即將關閉,做好準備,避免客戶端因“意外斷開”而出錯。
結束通信:先完成需要傳輸的數據,保證寫入緩衝區已清空。
調用socket_shutdown() :優雅關閉連接。
調用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_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()進行事件驅動處理,以實現更穩定的網絡服務。