php套接字偶尔没有响应,也没有抛出任何错误

时间:2012-11-16 16:54:36

标签: php sockets flex

我在服务器端使用MySQLPHP编写了一个数据库应用程序,在客户端使用Flex。我使用php套接字让它在数据库发生变化时自动更新所有客户端。

整个系统都在游泳,但是插座似乎不时响应。奇怪的是连接仍然很好 - 客户端执行的任何更改都已实现,但套接字不会广播该消息。套接字文件没有抛出任何错误(但是当我从套接字运行error_log时出现这些消息)。服务器上的内存使用不会改变,也不会发送断开信号。更奇怪的是,大约半小时后,套接字最终再次开始工作。如果我重新启动也能解决问题的套接字。

我正在开发一个hacky解决方案,允许客户端重新启动套接字,如果它没有响应,但这是不满意的,并且容易出错。我真正想要的是了解为什么会发生这种情况。在一定数量的连接后,套接字是否会以某种方式“饱和”?我应该做些什么来清理套接字服务器吗?我尝试过三种不同的物理服务器(一种是本地服务器,两种是在线服务器),同样的事情发生了,所以肯定是我。

我觉得我有一些基本的错误。这是我用于套接字服务器的代码(它是由Raymond Fain在kirupa.com上编写的一个稍微修改过的套接字版本,因此我将其原始评论留在顶部):

#!/usr/bin/php -q
<?php
/*
Raymond Fain
Used for PHP5 Sockets with Flash 8 Tutorial for Kirupa.com
For any questions or concerns, email me at ray@obi-graphics.com
or simply visit the site, www.php.net, to see if you can find an answer.
*/

//ini_set('display_errors',1);
//ini_set('display_startup_errors',1);
error_reporting(E_ALL);
ini_set('error_log', 'socket_errors.log');
ini_set('log_errors', 'On');
ini_set('display_errors', 'Off');

set_time_limit(0);

ob_implicit_flush();

error_log('testing');

$address = 'xxx.xxx.xx.xx';
$port = xxxxx;

function send_Message($allclient, $socket, $buf)
{
    $buf = str_replace("\0","",$buf);
    //echo "<mbFeed>$buf</mbFeed>\n\0";
    foreach($allclient as $client)
    {
        socket_write($client, "<mbFeed>$buf</mbFeed>\n\0");
    }
}


echo "connecting...
";
//---- Start Socket creation for PHP 5 Socket Server -------------------------------------

if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
    echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}

socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);


if (($ret = socket_bind($master, $address, $port)) < 0)
{
    echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}

echo 'socket bind successfull.
';


if (($ret = socket_listen($master, 5)) < 0)
{
    echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}

$read_sockets = array($master);

echo "connected.";

//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while (true)
{ 
    $changed_sockets = $read_sockets;
    $num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
    foreach($changed_sockets as $key => $socket)
    {
        if ($socket == $master)
        {
            if (($client = socket_accept($master)) < 0)
            {
                echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
                continue;
            } 
            else
            {
                array_push($read_sockets, $client);
            }
        }
        else
        {
            $bytes = socket_recv($socket, $buffer, 8192, 0);

            if ($bytes == 0)
            {
                unset($read_sockets[$key]);
                unset($changed_sockets[$key]);
                socket_close($socket);
            }
            else
            {
                $allclients = $read_sockets;
                array_shift($allclients);
                //any messages starting with ::: are not to be broadcast, and may be used for other things. This message
                //usually comes from the client.
                if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
                else
                {
                    //otherwise the message comes from a php file that will be closed, so the socket needs to be closed.
                    unset($read_sockets[$key]);
                    unset($changed_sockets[$key]);
                    socket_close($socket);
                    send_Message($allclients, $socket, $buffer);
                }
            }
        }
    }
}

function handleSpecial($message)
{
    error_log($message);
}
?>

1 个答案:

答案 0 :(得分:0)

由于正在使用的套接字似乎阻塞,因此在读取请求的数据量之前,对socket_recv()的调用可能不会返回。并且这不会处理任何其他读取套接字,包括accecpting套接字。

要解决此问题,请使用socket_set_nonblock()使套接字解除阻止。请注意,在非阻塞套接字上调用socket_recv()可能会返回读取的字节数少于请求的字节数,因此应为每个套接字跟踪读取的数据量。