PHP Conference Japan 2024

socket_set_option

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

socket_set_option設定 Socket 的選項

說明

socket_set_option(
    Socket $socket,
    int $level,
    int $option,
    array|string|int $value
): bool

socket_set_option() 函式會將 socket 指定的選項,在指定的協定層級 level,設定為 value 參數所指向的值。

參數

socket

socket_create()socket_accept() 建立的 Socket 實例。

level

level 參數指定選項所在的協定層級。例如,要設定 socket 層級的選項,可以使用 level 參數 SOL_SOCKET。其他層級,例如 TCP,可以透過指定該層級的協定編號來使用。協定編號可以使用 getprotobyname() 函式找到。

option

可用的 socket 選項與 socket_get_option() 函式相同。

value

選項值。

返回值

成功時返回 true,失敗時返回 false

更新日誌

版本 說明
8.0.0 socket 現在是一個 Socket 實例;以前,它是一個 資源

範例

範例 #1 socket_set_option() 範例

<?php
$socket
= socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

if (!
is_resource($socket)) {
echo
'無法建立通訊端:'. socket_strerror(socket_last_error()) . PHP_EOL;
}

if (!
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
echo
'無法設定通訊端選項:'. socket_strerror(socket_last_error()) . PHP_EOL;
}

if (!
socket_bind($socket, '127.0.0.1', 1223)) {
echo
'無法綁定通訊端:'. socket_strerror(socket_last_error()) . PHP_EOL;
}

$rval = socket_get_option($socket, SOL_SOCKET, SO_REUSEADDR);

if (
$rval === false) {
echo
'無法取得通訊端選項:'. socket_strerror(socket_last_error()) . PHP_EOL;
} else if (
$rval !== 0) {
echo
'通訊端已設定 SO_REUSEADDR!' . PHP_EOL;
}
?>

另請參閱

新增註釋

使用者提供的註釋 8 則註釋

drenintell
19 年前
進一步闡述 "tim at e2-media dot co dot nz" 開始的內容。

SO_SNDTIMEO 是您可以搭配 socket_set_option 使用的眾多常數之一。

關於可用的預定義常數,請參閱 http://ca.php.net/manual/en/ref.sockets.php,並瀏覽 http://man.he.net/man2/setsockopt 以了解相關常數的含義。

Tim 的例子乍看之下可能有點不直觀,因為他使用了 SO_SNDTIMEO 常數。這表示,如果 socket 需要發送數據,它必須在指定的限制時間內完成,在他的例子中是 10 秒。通常情況下,您不會為發送數據設置逾時。然而,這個例子是有效的,而且在某些情況下您需要這樣做。

socket_set_option 更直觀的用法是為阻塞 socket(讀取時等待接收數據的 socket)設置逾時。您可以這樣做:

socket_set_option($socket,SOL_SOCKET, SO_RCVTIMEO, array("sec"=>0, "usec"=>100));

請注意 sec= 0 和 usec= 100;根據您希望程式等待接收數據的時間,您可能需要更改這些值。

此致,
drenintell
aeolianmeson at ifacfchi dot blitzeclipse dot com
16 年前
當您使用非阻塞 socket 時,延遲關閉有時會失效。即使 socket 設置為延遲關閉,並且您持續嘗試關閉直到 socket 不再返回錯誤且資源不再被識別為「Socket」類型,socket 仍然可能在未發送所有數據的情況下關閉。

因此,如果您正在使用非阻塞 socket(如果您關心信號,這是比較好的做法),您應該在調用關閉之前將 socket 設置為阻塞(socket_set_block())。這將允許所有數據在返回之前被清空。

Dustin Oprea
gmail 使用者 asmqb7
5 年前
請注意

PHP 7.3.6,以及之前的許多版本,在您使用 stream_socket_server() 時會自動設置 SO_REUSEADDR。

php_network_bind_socket_to_local_addr() 在 https://github.com/php/php-src/blob/623911f993f39ebbe75abe2771fc89faf6b15b9b/main/streams/xp_socket.c#L675 處被調用,並在 https://github.com/php/php-src/blob/61a6a6ec51297506c54f3c6e60ace9b892d0a3e4/main/network.c#L401 處定義,如果您看一下,您會看到

#ifdef SO_REUSEADDR
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
#endif

我最初以為我需要使用上下文選項來開啟它,但並不需要,最簡單的單參數調用,沒有錯誤檢查,只有一個地址,對我就有效。

使用 strace 追蹤您的 PHP 二進制文件以確保萬無一失

...
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
...

除非您在名稱中帶有 Z 的月份中使用 100 年前的 UNIX 副本,否則您很可能正在使用 SO_REUSEADDR。
renmengyang567 at gmail dot com
5 年前
<問題>
為什麼緩衝區的大小是我設置的 2 倍?
<?php
//設定快取區之前
$sock = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
socket_bind($sock, '127.0.0.1',5000);
socket_listen($sock,1024);
$sndbuf = socket_get_option($sock,SOL_SOCKET,SO_SNDBUF);
$rcvbuf = socket_get_option($sock,SOL_SOCKET,SO_RCVBUF);
printf("傳送緩衝區大小(寫緩衝區大小):%sm \n",$sndbuf/1024);
printf("接收緩衝區大小(讀緩衝區大小):%sm \n",$rcvbuf/1024);

//設定快取區之後
$snd_buf = 1024*3;
$rcv_buf = 1024*3;

socket_set_option($sock,SOL_SOCKET,SO_SNDBUF, $snd_buf);
socket_set_option($sock,SOL_SOCKET,SO_RCVBUF, $rcv_buf);
$sndbuf = socket_get_option($sock,SOL_SOCKET,SO_SNDBUF);
$rcvbuf = socket_get_option($sock,SOL_SOCKET,SO_RCVBUF);

printf("傳送緩衝區大小(寫緩衝區大小):%sm \n",$sndbuf/1024);
printf("接收緩衝區大小(讀緩衝區大小):%sm \n",$rcvbuf/1024);
?>
ludvig dot ericson at gmail dot com
17 年前
我想針對先前關於阻塞式通訊端(socket)的說明補充一些意見。
阻塞式通訊端不只是在嘗試讀取資料時等待資料接收,舉例來說,一個監聽中的阻塞式通訊端會在您使用 socket_accept() 接受連線之前,等待客戶端嘗試連線,然後才會返回。
tim at e2-media dot co dot nz
20 年前
要設定通訊端的逾時值(假設您已將其設定為阻塞式),請使用

socket_set_option(
$socket,
SOL_SOCKET, // 通訊端層級
SO_SNDTIMEO,// 超時選項
陣列(
"sec"=>10, // 超時秒數
"usec"=>0 // 我猜是超時微秒數
)
);
DaveRandom
14 年前
在 Windows 系統下,至少在 PHP/5.2.9 版本中,設定 socket 超時微秒數 ('usec') 無效。

<?php

$timeout
= array('sec'=>1,'usec'=>500000);
socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,$timeout);
var_dump(socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO));

?>

Windows 系統上的輸出

陣列(2) {
["sec"]=>
int(1)
["usec"]=>
int(0)
}

Linux 系統上的輸出

陣列(2) {
["sec"]=>
int(1)
["usec"]=>
int(500000)
}
ckozler at kozler dot net
12 年前
看來 Winsock 在 Windows 上並未處理超時(傳送和接收)。
To Top