我正在使用PHP Websocket,有时会同时收到以下两个警告。
警告-1:
socket_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的命令
socket_recv():远程主机强行关闭了现有连接
是:
while(socket_recv($ newSocketArrayResource,$ socketData,1024,0)> = 1)
在PHP-Manual中提到要获取socket_recv()的返回值。但是在示例中,仅显示通过使用if()执行一次socket_recv()。
但是我在循环头中使用了socket_recv()。
所以我的问题是:
我该如何检查返回值-通过在循环头中使用socket_recv()?
警告2
socket_getpeername():无法检索对等名称[107]:传输端点未连接
是使用以下代码生成的:
socket_getpeername($ newSocketArrayResource,$ client_ip_address);
我的问题是:
如果客户端不再连接,我该怎么办才能不执行socket_getpeername()?
也许有人可以帮助我修复这些警告。观看非常困难,因为这些警告并不总是出现。
再见, 克里斯
答案 0 :(得分:0)
我该如何检查返回值-通过在循环头中使用socket_recv()?
您可以捕获socket_recv的返回值并检查它的值,但是按照正确的顺序进行操作很重要,并且可以使用()来指示php以哪个顺序进行操作,例如:>
while(($bytes_recieved=socket_recv($newSocketArrayResource, $socketData, 1024, 0)) >= 1)
{
// now you can check it inside the loop, it's $bytes_recieved
}
// you can also check it outside the loop, it's still in $bytes_recieved
(但是,请注意,如果您将()的位置错误,它将变成> =的布尔结果,例如,这是错误的:while($bytes_recieved=(socket_recv($newSocketArrayResource, $socketData, 1024, 0) >= 1))
,与此相反,$ bytes_recieved会变成>=
的布尔结果。)
如果客户端不再连接,我该怎么办才能不执行socket_getpeername()?
好吧,如果您应用上述补丁,我想您可以检查$ bytes_recieved是否为真,例如
if (!!$bytes_recieved) {
socket_getpeername($newSocketArrayResource, $client_ip_address);
$newSocketIndex = array_search($newSocketArrayResource, $clientSocketArray);
unset($clientSocketArray[$newSocketIndex]);
}
执行!!
会将其转换为bool(true-ish),如果客户端仍处于连接状态,则可能为true-ish,否则可能为false-ish。 -尽管,如果客户端一段时间不发送任何字节,这可能会导致误报,因此检查它是否直接为假(而不是假冒)可能更安全,您可以使用===
进行检查,例如
if ($bytes_recieved === false) {
socket_getpeername($newSocketArrayResource, $client_ip_address);
$newSocketIndex = array_search($newSocketArrayResource, $clientSocketArray);
unset($clientSocketArray[$newSocketIndex]);
}
...顺便说一句,我不确定,但是看起来您的代码只是随机选择一个共享$ newSocketArrayResource ip地址的客户端,而不是专门选择$ newSocketArrayResource。如果您的服务器每个IP地址永远不会收到超过1个连接,我想这是可以的(仍然是一个糟糕的设计选择,imo,但不是直接出错),但是我认为您应该通过资源ID(而不是IP地址)选择客户端,则您的服务器将能够为每个IP地址支持多个1个连接。我认为您应该将密钥设置为资源ID,而是这样做:
if ($bytes_recieved === false) {
unset($clientSocketArray[(int)$newSocketArrayResource]);
}
...最后,看起来您这里有资源泄漏,只是取消设置它就会留下内存泄漏(和处理泄漏),我想您想要的是
if ($bytes_recieved === false) {
unset($clientSocketArray[(int)$newSocketArrayResource]);
socket_close($clientSocketArray);
}
这将使您没有内存/句柄泄漏。