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 设置指定协议 level 上由参数 option 指定的选项,值为参数 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 则注释

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
1
aeolianmeson at ifacfchi dot blitzeclipse dot com
16 年前
在使用非阻塞套接字时,延迟有时不起作用。即使套接字设置为延迟,并且您一直尝试关闭,直到套接字不再返回错误并且资源不再可识别为类型 'Socket',套接字可能仍然会关闭而没有发送所有内容。

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

Dustin Oprea
0
gmail user 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

我最初以为需要玩弄上下文选项才能打开它,但事实并非如此,最简单的单参数调用,没有错误检查,只有一个地址,对我来说已经足够了。

对您的 PHP 二进制文件执行 strace 以确保 100%

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

除非您使用的是一个在有 Z 的月份里运行的 100 年前的 UNIX 克隆,否则您很有可能正在使用 SO_REUSEADDR。
0
renmengyang567 at gmail dot com
5 年前
<问题>
为什么缓冲区的大小是我设置的两倍?
<?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);
?>
0
ludvig dot ericson at gmail dot com
17 年前
我想评论一下之前关于阻塞套接字的说明。
阻塞套接字不仅仅是在读取数据时等待数据接收,举个例子,一个监听阻塞套接字会在 socket_accept() 返回之前等待客户端尝试连接。
0
tim at e2-media dot co dot nz
20 年前
要设置套接字超时值(假设你已将其设置为阻塞),请使用

socket_set_option(
$socket,
SOL_SOCKET, // 套接字级别
SO_SNDTIMEO, // 超时选项
array(
"sec"=>10, // 超时时间(秒)
"usec"=>0 // 我假设超时时间是微秒
)
);
-2
DaveRandom
13 年前
在 Windows 下,至少在 PHP/5.2.9 下,设置套接字超时微秒('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 机器上的输出

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

Linux 机器上的输出

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