我有一个奇怪的问题,可能是由于我对套接字编程经验不足。
我目前正在使用我从socket_last_error()
获取的原始错误代码,因为我看到我需要处理它们。这变得笨拙。
我想使用预定义的常量(我自己的或内置的)来引用我需要处理的不同类型的套接字错误/条件。
我发现的错误表都使用了冲突的值。
在http://php.net/manual/en/sockets.constants.php(在列出原始数字的评论中),我看到的内容如下(摘录):
SOCKET_EINPROGRESS 10036
SOCKET_EALREADY 10037
SOCKET_ENETUNREACH 10051
http://php.net/socket_last_error处的一条评论包含一个显然是"标准C定义"的列表。套接字错误(?):
define('EINPROGRESS', 115); /* Operation now in progress */
define('EALREADY', 114); /* Operation already in progress */
define('ENETUNREACH', 101); /* Network is unreachable */
我自己系统上的errno.h文件(隐藏在/ usr / include / asm-generic /中)似乎支持这个:
#define EINPROGRESS 115 /* Operation now in progress */
#define EALREADY 114 /* Operation already in progress */
#define ENETUNREACH 101 /* Network is unreachable */
然而,那些"标准定义"似乎可能会有所变化,具体取决于您所使用的操作系统:BSD4.4's errno.h有类似的内容
#define EINPROGRESS 36 /* Operation now in progress */
#define EALREADY 37 /* Operation already in progress */
#define ENETUNREACH 51 /* Network is unreachable */
现在我们知道socket_*
函数的灵感来自于什么!
最后,我发现似乎隐藏在the VirtualBox source code中的一个解释暗示:
#ifndef EALREADY
# if defined(RT_ERRNO_OS_BSD)
# define EALREADY (37)
# elif defined(RT_OS_LINUX)
# define EALREADY (114)
# else
# define EALREADY (149)
# endif
#endif
将所有这些考虑在内......
socket_last_error()
在errno
时返回101
Network is unreachable
,而不是51
或10051
。所以这个函数似乎明显违反了套接字库的官方提供的常量,而且似乎正在使用Linux的错误代码。
([添加我的回答后编辑]:上面提到的101
是在Linux上获得的。)
所以现在我似乎处于无证和/或看似未定义的行为领域......我现在该怎么办?我现在在Linux上;这些价值观会发生变化吗?
有什么方法可以使用官方SOCKET_*
常量吗?我当然不会这么做。
答案 0 :(得分:1)
我只是做了一些挖掘。
socket_*
常量兼容的错误代码,因此您必须检测操作系统:'(查看源代码后的证据。
以下内容被大大减少以帮助集中注意力。
来自https://github.com/php/php-src/blob/master/ext/sockets/sockets.c:
PHP_FUNCTION(socket_connect) {
// will set errno
retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
if (retval != 0) {
// call macro defined in php_sockets.h with errno value
PHP_SOCKET_ERROR(php_sock, "unable to connect", errno);
RETURN_FALSE;
}
RETURN_TRUE;
}
PHP_FUNCTION(socket_last_error) {
// check for argument
if (arg1) {
if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) {
RETURN_FALSE;
}
// return errno from passed socket resource
RETVAL_LONG(php_sock->error);
} else {
// return errno from last globally set value
RETVAL_LONG(SOCKETS_G(last_error));
}
}
来自https://github.com/php/php-src/blob/master/ext/sockets/php_sockets.h:
#define PHP_SOCKET_ERROR(socket, msg, errn) \
// store the value for this socket resource
(socket)->error = _err; \
// store the value globally
SOCKETS_G(last_error) = _err
证明:
<?php
$s = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($s);
socket_connect($s, "google.com", "80");
var_dump(socket_last_error());
var_dump(socket_strerror(socket_last_error()));
观察socket_last_error()
:
linux$ php asdf.php
int(115)
string(25) "Operation now in progress"
freebsd$ php asdf.php
int(36)
string(25) "Operation now in progress"
TL; DR:PHP中没有已定义的常量列表(我可以看到如何使用)。您必须提供自己的操作系统正确的常量列表。
答案 1 :(得分:1)
听起来你一直在努力研究这个问题 - 而且平台特定的东西可能会令人讨厌。让我建议这个代码表面上将所有定义的常量组合在一起作为&#34;套接字&#34;常量:
$consts = get_defined_constants(TRUE);
$socket_constants = $consts["sockets"];
foreach($socket_constants as $key => $value){
echo $key . '=' . $value . "\n";
}
由此,我能够构建这个函数,您可以在任何平台上找到有用的函数来查找可能匹配的套接字常量的名称
function get_socket_constant_names($to_check) {
$consts = get_defined_constants(TRUE);
$socket_constants = $consts["sockets"];
$matches = array();
foreach($socket_constants as $key => $value){
if ($value == $to_check) {
$matches[] = $key;
}
}
return $matches;
}
这:
var_dump(get_socket_constant_names(101));
产生这个:
array(1) {
[0] =>
string(18) "SOCKET_ENETUNREACH"
}