使用PHP套接字模块检测对等断开连接(EOF)

我对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";

}

上面的代码只是连接到服务器并打印它读取的内容.它是我正在编写的小型套接字库中的缩减版本.

为了测试,我目前正在使用ncat -vvklp 8081绑定套接字并成为服务器.随着运行,我可以启动上面的代码,它连接和工作 – 例如,我可以键入ncat窗口,PHP接收它. (从PHP发送数据也有效,但我已将该代码排除在外,因为它不相关.)

然而,在I ^ C ncat的那一刻,上面的代码进入了一个硬无限循环 – 而且PHP说套接字上没有错误.

我试图弄清楚按钮在哪里打击PHP头部并使其意识到对等已断开连接.

> socket_get_status()是一个很大的用词 – 它是stream_get_meta_data()的别名,它实际上不适用于套接字!
> feof()类似spouts警告:feof():提供的资源不是有效的流资源.

我找不到用于检测对等EOF的socket_ *函数.

One of the PHP manual notes for socket_read()最初阻止我使用该函数,所以我使用了socket_recv()代替,但我最终尝试了以防万一 – 但没有骰子;切换接收呼叫无效.

我发现看着套接字进行写入然后尝试写入它会突然让PHP变成“哦,等等,正确”并开始返回Broken pipe – 但我对写入服务器不感兴趣,我想阅读从中!

最后,关于注释部分 – 我更倾向于使用PHP的内置流功能,但是stream_ *函数没有提供任何处理异步连接事件的方法(我想做,因为我正在建立多个连接).我可以做stream_socket_client(… STREAM_CLIENT_ASYNC_CONNECT …),但后来找不到连接何时建立(6yo PHP bug #52811).

最佳答案
好吧,我想我也可以将上面的评论转化为答案.所有的功劳都归功于Ryan Vincent,因为我帮助了我的厚脸皮,

如果对等方已断开连接,socket_recv将返回0,如果发生任何其他网络错误,则返回FALSE.

作为参考,在C中,recv()的返回值是您刚收到的新数据的长度(可以是0),或-1表示错误条件(其值可以在errno中找到) ).

使用0表示错误条件(并且只有一种任意类型的错误条件)在PHP中并不是标准的,并且在所有错误的方式上都是唯一的.其他网络库不以这种方式工作.

你需要像这样处理它.

$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).

}

转载注明原文:使用PHP套接字模块检测对等断开连接(EOF) - 代码日志