提问人:i336_ 提问时间:9/9/2016 更新时间:9/16/2016 访问量:2509
检测与 PHP 套接字模块的对等断开连接 (EOF)
Detecting peer disconnect (EOF) with PHP socket module
问:
我在使用 PHP 的套接字库时遇到了一个奇怪的问题:我似乎无法检测/区分服务器 EOF,结果我的代码无助地进入了无限循环。
下文作进一步解释;首先,一些背景(这里没有什么特别花哨的事情):
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '127.0.0.1', 8081);
for (;;) {
$read = [$socket];
$except = NULL;
$write = [];
print "Select <";
$n = socket_select($read, $write, $except, NULL);
print ">\n";
if (count($read)) {
print "New data: ";
#socket_recv($socket, $data, 1024, NULL);
$data = socket_read($socket, 1024);
print $data."\n";
}
print "Socket status: ".socket_strerror(socket_last_error())."\n";
}
上面的代码只是连接到服务器并打印它读取的内容。这是我正在编写的小型套接字库中的精简版本。
为了进行测试,我目前正在使用绑定套接字并成为服务器。运行后,我可以启动上面的代码,它连接并工作 - 例如,我可以在窗口中输入,PHP 接收它。(从PHP发送数据也可以,但是我排除了该代码,因为它不相关。ncat -vvklp 8081
ncat
然而,当 I ^C
ncat
的那一刻,上面的代码进入了一个硬无限循环 - PHP 说套接字上没有错误。
我试图弄清楚按钮在哪里,它使PHP颠倒在头上,并使其意识到对等方已断开连接。
socket_get_status()
是一个很大的用词不当 - 它是 的别名,它实际上不适用于套接字!stream_get_meta_data()
feof()
类似的喷口.Warning: feof(): supplied resource is not a valid stream resource
我找不到用于检测对等 EOF 的函数。socket_*
socket_read()
的 PHP 手册之一最初劝阻我不要使用该函数,所以我改用了该函数,但我最终尝试了它以防万一 - 但没有骰子;切换接收呼叫不起作用。socket_recv()
我发现观察套接字进行写入,然后尝试写入它会突然让 PHP 去“哦,等等,对”并开始返回 Broken pipe
- 但我对写入服务器不感兴趣,我想从中读取!
最后,关于注释部分 - 我更愿意使用 PHP 的内置流功能,但这些函数没有提供任何处理异步连接事件的方法(我想这样做,因为我正在建立多个连接)。我可以做,但无法找出何时建立连接(6yo PHP bug #52811)。stream_*
stream_socket_client(... STREAM_CLIENT_ASYNC_CONNECT ...)
答:
好吧,我想我不妨把上面的评论变成答案。所有的功劳都归功于瑞安·文森特(Ryan Vincent)帮助我的厚实的头脑弄清楚了这一点:)
socket_recv
如果对等体已断开连接,或者发生任何其他网络错误,将特别返回。0
FALSE
作为参考,在 C 中,的返回值是您刚刚收到的新数据的长度(可以是 ),或者表示错误条件(其值可以在 中找到)。recv()
0
-1
errno
用来表示错误条件(并且只是一种任意类型的错误条件)不是 PHP 的标准和唯一错误方式。其他网络库不以这种方式工作。0
你需要这样处理它。
$r = socket_recv($socket, $buf, $len);
if ($r === FALSE) {
// Find out what just happened with socket_last_error()
// (there's a great list of error codes in the comments at
// http://php.net/socket_last_error - considering/researching
// the ramifications of each condition is recommended)
} elseif ($r === 0) {
// The peer closed the connection. You need to handle this
// condition and clean up.
} else {
// You DO have data at this point.
// While unlikely, it's possible the remote peer has
// sent you data of 0 length; remember to use strlen($buf).
}
评论
socket_select
socket_select