在PHP 網絡編程中,處理多路復用(Multiplexing)是實現高效網絡服務的關鍵技術。 socket_set_option和socket_select作為PHP socket 編程中的兩個重要函數,很多開發者會疑惑它們是否可以一起使用,尤其是在實現多路復用時該如何正確搭配。
本文將詳細講解socket_set_option和socket_select的作用,探討它們能否一起用,並介紹如何用它們實現多路復用。
socket_set_option用於給套接字設置選項,比如超時時間、是否重用地址、發送/接收緩衝區大小等。它的作用是調整socket 的行為特性。
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
上面代碼為socket 設置了地址重用選項,常用於服務器重啟時快速綁定端口。
socket_select是實現多路復用的關鍵函數。它用於監聽多個socket,當其中一個或多個socket 準備好讀寫時,函數返回。這樣可以讓單線程程序同時處理多個連接。
$read = [$socket1, $socket2];
$write = null;
$except = null;
$timeout = 5;
$num_changed = socket_select($read, $write, $except, $timeout);
socket_select通過修改$read 、 $write 、 $except數組來返回那些準備好的socket。
答案是可以,但兩者功能不同,配合使用時應清晰區分用途:
socket_set_option用於配置socket 的行為(比如超時、緩衝區等)。
socket_select用於監聽多個socket 是否可讀、可寫或有異常。
多路復用主要依賴socket_select ,而socket_set_option只是調整socket 的屬性,通常是在socket 創建後、 socket_select使用前設置。
以下是一個簡單的服務器示例,展示如何用socket_set_option設置socket 選項,同時使用socket_select實現多路復用監聽多個客戶端連接。
<?php
// 創建 TCP socket
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
// 綁定端口
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);
$clients = [];
$read = [$server];
while (true) {
$readSockets = $read;
$write = null;
$except = null;
// 監聽多個 socket 的變化
$numChanged = socket_select($readSockets, $write, $except, 5);
if ($numChanged === false) {
echo "socket_select 出錯\n";
break;
} elseif ($numChanged > 0) {
// 監聽到新的客戶端連接
if (in_array($server, $readSockets)) {
$newClient = socket_accept($server);
if ($newClient !== false) {
socket_set_option($newClient, SOL_SOCKET, SO_RCVTIMEO, ["sec"=>5, "usec"=>0]);
$clients[] = $newClient;
$read[] = $newClient;
echo "新客戶端連接\n";
}
unset($readSockets[array_search($server, $readSockets)]);
}
// 處理已有客戶端發送的數據
foreach ($readSockets as $socket) {
$data = socket_read($socket, 1024, PHP_NORMAL_READ);
if ($data === false || $data === '') {
// 連接關閉
socket_close($socket);
unset($clients[array_search($socket, $clients)]);
unset($read[array_search($socket, $read)]);
echo "客戶端斷開\n";
} else {
$data = trim($data);
echo "收到客戶端數據: $data\n";
// 發送響應
socket_write($socket, "服務器已收到: $data\n");
}
}
}
}
socket_close($server);
關鍵點說明:
服務器套接字$server用socket_set_option設置了SO_REUSEADDR ,保證端口快速重用。
新客戶端連接建立後,也用socket_set_option設置了接收超時選項。
socket_select監聽所有活躍的客戶端socket 和服務器socket,確保多路復用機制正常工作。
socket_set_option和socket_select功能不同,但可以且應該結合使用。
socket_set_option負責配置socket 參數,優化網絡性能和行為。
socket_select負責多路復用,監聽多個socket 事件。
合理使用這兩個函數,能夠寫出高效、穩定的網絡服務器程序。
如果想深入學習PHP socket 多路復用,也可以參考官方文檔及相關網絡編程書籍,掌握更多細節和高級技巧。
文章中示例的URL 域名如下:
$url = "https://gitbox.net/api/socket_demo";