PHP Conference Japan 2024

socket_set_option

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

socket_set_option设置套接字的套接字选项

说明

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

socket_set_option() 函数为 socket 套接字设置 option 参数指定的在协议 level 层的选项为 value 参数指向的值。

参数

socket

一个用 socket_create()socket_accept() 创建的 Socket 实例。

level

level 参数指定选项所在的协议级别。例如,要在套接字级别设置选项,需要使用 level 参数 SOL_SOCKET。其它级别,例如 TCP,可以通过指定该级别的协议号来使用。协议号可以通过使用 getprotobyname() 函数找到。

option

可用的套接字选项与 socket_get_option() 函数相同。

value

选项的值。

返回值

成功时返回 true,失败时返回 false

更新日志

版本 说明
8.0.0 socket 现在是一个 Socket 实例;之前,它是一个 resource

示例

示例 #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 条注释

up
7
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 常量。这意味着,如果套接字必须发送数据,则必须在指定的限制内完成 - 在他的情况下是 10 秒。通常,您不会为发送数据设置超时。尽管如此,该示例是有效的,并且在某些情况下您需要这样做。

更直观地使用 socket_set_option 的方法是为阻塞式套接字(读取时等待数据接收的套接字)设置超时。您可以这样做:

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

请注意 sec= 0 且 usec= 100;根据您希望程序等待接收数据的时间长短,您可能需要更改这些值。

此致,
drenintell
up
1
aeolianmeson at ifacfchi dot blitzeclipse dot com
16 年前
当您使用非阻塞套接字时,延迟有时不起作用。即使套接字设置为延迟并且您不断尝试关闭直到套接字不再返回错误并且资源不再被识别为“Socket”类型,套接字仍然可能在没有发送所有内容的情况下关闭。

因此,如果您使用非阻塞套接字(如果您关心信号处理,这是更好的选择),您应该在调用关闭之前将套接字设置为阻塞 (socket_set_block())。这将允许在返回之前刷新所有内容。

Dustin Oprea
up
0
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 二进制文件以 100% 确定

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

除非您在一个包含 Z 的月份使用一个 100 年历史的 UNIX 克隆,否则您很可能正在使用 SO_REUSEADDR。
up
0
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);
?>
up
0
ludvig dot ericson at gmail dot com
17 年前
我想对之前关于阻塞套接字的说明发表评论。
阻塞套接字不仅仅是在尝试读取时等待接收数据,例如,当您使用 socket_accept() 时,侦听阻塞套接字将等待客户端尝试连接,然后才返回。
up
0
tim at e2-media dot co dot nz
20 年前
要设置套接字超时值(假设您已将其设置为阻塞),请使用

socket_set_option(
$socket,
SOL_SOCKET, // 套接字级别
SO_SNDTIMEO, // 超时选项
array(
"sec"=>10, // 超时时间(秒)
"usec"=>0 // 我假设是微秒超时
)
);
up
-2
DaveRandom
14 年前
在 Windows 下设置套接字超时微秒('usec')不起作用,至少在 PHP/5.2.9 下

<?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 机器上的输出

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

Linux 机器上的输出

array(2) {
["sec"]=>
int(1)
["usec"]=>
int(500000)
}
up
-5
ckozler at kozler dot net
12 年前
看来 Winsock 在 Windows 上不识别超时(发送和接收)。
To Top