PHP Websocket:socket_recv()和socket_getpeername()的问题

PHP Websocket:socket_recv()和socket_getpeername()的问题,php,sockets,websocket,Php,Sockets,Websocket,我正在使用PHP Websocket,有时会收到以下两个警告。 警告-1: 套接字_recv():远程主机强制关闭了现有连接 警告2: socket_getpeername():无法检索对等名称[107]:未连接传输终结点 我通过另一个PHP脚本向Websocket发送消息。此PHP脚本发送一条消息,如果消息完成,套接字调用将结束 因此,此警告可能是正确的,因为“端点”(=PHP脚本)未连接记录器。 但是这个警告并不漂亮。 下面是接收消息的Websocket的代码: define('HOST_N

我正在使用PHP Websocket,有时会收到以下两个警告。
警告-1:

套接字_recv():远程主机强制关闭了现有连接

警告2:

socket_getpeername():无法检索对等名称[107]:未连接传输终结点

我通过另一个PHP脚本向Websocket发送消息。此PHP脚本发送一条消息,如果消息完成,套接字调用将结束
因此,此警告可能是正确的,因为“端点”(=PHP脚本)未连接记录器。
但是这个警告并不漂亮。

下面是接收消息的Websocket的代码:

define('HOST_NAME',$host_ip); 
define('PORT',$socket_port);

$null = NULL;

$socketHandler = new SocketHandler();

$socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socketResource, 0, PORT);
socket_listen($socketResource);

$clientSocketArray = array($socketResource);
while (true) {

    $newSocketArray = $clientSocketArray;
    socket_select($newSocketArray, $null, $null, 0, 10);

    if (in_array($socketResource, $newSocketArray)) {
        $newSocket = socket_accept($socketResource);
        $clientSocketArray[] = $newSocket;

        $header = socket_read($newSocket, 1024);
        $socketHandler->doHandshake($header, $newSocket, HOST_NAME, PORT);

        socket_getpeername($newSocket, $client_ip_address);

        $newSocketIndex = array_search($socketResource, $newSocketArray);
        unset($newSocketArray[$newSocketIndex]);
    }
    foreach ($newSocketArray as $newSocketArrayResource) {  
    while(socket_recv($newSocketArrayResource, $socketData, 1024, 0) >= 1){

            $socketMessage = $socketHandler->unseal($socketData);
            $messageObj = json_decode($socketMessage);

            break 2;
        }
        $socketData = @socket_read($newSocketArrayResource, 1024, PHP_NORMAL_READ);

        if ($socketData === false) { 
            socket_getpeername($newSocketArrayResource, $client_ip_address);
            $newSocketIndex = array_search($newSocketArrayResource, $clientSocketArray);
            unset($clientSocketArray[$newSocketIndex]);         
        }
    }
}
socket_close($socketResource);
生成警告-1的命令

套接字_recv():远程主机强制关闭了现有连接

是:

而(socket_recv($newsocketarayresource,$socketData,1024,0)>=1)

在中提到了获取socket_recv()的返回值。但在示例中,只显示了使用if()执行套接字_recv()一次
但是我在循环头中使用socket_recv()
所以我的问题是:
在我的例子中,如何检查返回值-在循环头中使用socket_recv()

警告-2

socket_getpeername():无法检索对等名称[107]:未连接传输终结点

已使用以下代码生成:

socket\u getpeername($newsocketarray资源,$client\u ip\u地址)

我的问题是:
如果客户端不再连接,我应该怎么做才能不执行socket_getpeername()

也许有人能帮我修复这些警告。很难观看,因为这些警告并不总是出现

再见, 克里斯

在我的例子中,如何检查返回值-在循环头中使用socket_recv()

您可以捕获socket_recv的返回值并检查它的值,但重要的是要按照正确的顺序执行,并且您可以通过使用()来指定php执行的顺序,例如:

(但是,请注意,如果您将()放错,它将改为>=的bool结果,例如,这是错误的:
而($bytes\u received=(socket\u recv($newsocketarayresource,$socketData,1024,0)>=1))
,使用此选项,$bytes\u received将改为
=/code>的bool结果)

如果客户端不再连接,我应该怎么做才能不执行socket_getpeername()

好的,如果你应用上面的补丁,我想你可以检查$bytes_received是否为true,例如

    if (!!$bytes_recieved) { 
        socket_getpeername($newSocketArrayResource, $client_ip_address);
        $newSocketIndex = array_search($newSocketArrayResource, $clientSocketArray);
        unset($clientSocketArray[$newSocketIndex]);         
    }
  • 正在执行
    将其转换为bool(true ish),如果客户端仍然连接,则可能为true ish,否则可能为false ish。-尽管如此,如果客户端一段时间内没有发送任何字节,这可能会得到误报,因此更安全的方法是直接检查它是否为false,而不是使用false-ish,您可以使用
    ==
    ,例如

    if ($bytes_recieved === false) { 
        socket_getpeername($newSocketArrayResource, $client_ip_address);
        $newSocketIndex = array_search($newSocketArrayResource, $clientSocketArray);
        unset($clientSocketArray[$newSocketIndex]);         
    }
    
。。。顺便说一句,我不确定,但这里的代码似乎只是随机选择了一个共享$newsocketarayresource的ip地址的客户端,而不是专门选择$newsocketarayresource。如果您的服务器从未收到每个ip地址超过1个连接,我想这是可以的(依我看,这仍然是一个糟糕的设计选择,但没有直接安装错误),但我认为您应该根据资源id而不是ip地址来选择客户机,那么您的服务器将能够支持每个ip地址超过1个连接。我认为您应该将密钥设置为资源id,并执行以下操作:

    if ($bytes_recieved === false) { 
        unset($clientSocketArray[(int)$newSocketArrayResource]);
    }
。。。最后,看起来您这里有一个资源泄漏,如果不解决它,将导致内存泄漏(以及处理泄漏),我认为您需要:

    if ($bytes_recieved === false) {
        unset($clientSocketArray[(int)$newSocketArrayResource]);
        socket_close($clientSocketArray);
    }

这将使您没有内存/处理泄漏。

感谢您的回答。我用“while($bytes_received=socket_recv..”尝试了您的示例,但警告已经出现:“PHP警告:socket_recv():无法从socket读取[10053]:socket错误10053-主机中的软件中止了已建立的连接”。因此,为了获取$bytes_received的返回值,socket_recv()必须首先执行返回值。我想我必须首先检查客户端是否仍然连接,如果仍然连接,我可以调用socket_recv()但是我不知道在执行socket_recv之前我必须检查什么。你有什么想法吗?@Funkfeuer你是在问
如何获取socket_recv的返回值并隐藏警告消息
?在这种情况下,答案是
而($bytes_received=@socket_recv($newsocketarayresource,$socketData,1024,0))>=1)
是的,你说得对。通过使用while($bytes\u received=@socket\u recv($newsocketarayresource,$socketData,1024,0))>=1)我得到了返回值,但警告仍然伴随着它出现。我该如何处理socket\u recv()是否不生成警告?@Funkfeuer如果警告仍然出现,则在php.ini中将
xdebug.scream
设置为
0
,或者在抛出警告之前教您的自定义set\u error\u handler()函数检查活动的错误报告()级别。
if(!(error\u reporting()&$severity)){/*由于错误而被忽略,报告级别为*/return;}
xdebug说:
PHP堆栈跟踪:php1.{main}()C:\xampp\htdocs\TEST\socket\server.PHP:0 php2.socket\recv()C:\xampp\htdocs\TEST\socket\server.PHP:67警告:socket\u recv():无法从socket读取[10053]:主机中的软件中止了已建立的连接。在第67行的C:\xampp\htdocs\TEST\socket\u server.php中,调用堆栈:0.0004 392096 1.{main}()C:\xampp\htdocs\TEST\socket\u server.php:0 77.2232 503704 2.socket\u recv()C:\xampp\htdocs\TEST\socket\u server.php:67
    if ($bytes_recieved === false) {
        unset($clientSocketArray[(int)$newSocketArrayResource]);
        socket_close($clientSocketArray);
    }