我正在运行一个基于Raymond Fain教程在kirupa上提供的php服务器:
http://www.kirupa.com/developer/flash8/php5sockets_flash8_3.htm
它很有效,但在某种程度上。问题是,当它收到某些消息时,它会对该消息执行一些操作,然后将其发送给所有连接的客户端。这里的问题是,一旦客户端数量达到大约12的大气高度,将消息发送到所有客户端的循环可能需要一段时间(如4秒),并且在该4秒时间段内发送的任何后续消息排队等待最终我们得到了超时。
这是向所有客户端发送消息的循环:
function send_Message($allclient, $socket, $buf)
{
$now = microtime(true);
echo 'sending message to '.count($allclient).' clients ';
$msg = "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, $msg, strlen($msg));
}
$end = microtime(true);
echo 'time was '.($end - $now);
}
你会注意到我通过比较微量时间来回应它所花费的时间。问题在于回声声称整个过程需要花费很少的时间,比如0.003秒,这是我所期望的,但是当我在终端中运行这个脚本时,我看到了一个小旋转图标。四秒钟,在此期间一切都没有反应。
我的问题如下:有没有人知道脚本在那段时间做了什么?我有什么办法可以阻止它这样做吗?有没有更有效的方法将消息发送到所有连接的套接字?
这是整个套接字文件的代码,如果你需要的话,但是我希望这对某些人来说可能是熟悉的......
#!/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', '1');
error_log('testing');
stream_set_timeout(1,0);
set_time_limit(0);
ob_implicit_flush();
$address = 'xxx.xxx.x.xxx';
$port = xxxx;
function send_Message($allclient, $socket, $buf)
{
$now = microtime(true);
echo 'sending message to '.count($allclient).' clients ';
$msg = "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, $msg, strlen($msg));
}
$end = microtime(true);
echo 'time was '.($end - $now);
}
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);
socket_set_nonblock($master);
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);
echo 'changed sockets length: '.(count($changed_sockets));
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
{
socket_set_nonblock($client);
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
{
if (substr($buffer, 0, 3) == "<->")
{
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
$buffer = substr($buffer, 3);
}
$allclients = $read_sockets;
array_shift($allclients);
if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
else
{
echo 'allclients length: '.(count($allclients));
send_Message($allclients, $socket, str_replace("\0","",$buffer));
}
}
}
}
}
?>
答案 0 :(得分:1)
我建议你看看ZeroMQ类似于类固醇的插座
一百字的ØMQ
ØMQ(也称为ZeroMQ,0MQ,zmq)看起来像一个可嵌入的网络库,但就像一个并发框架。它为您提供了在各种传输中传输原子消息的套接字,如进程内,进程间,TCP和多播。您可以使用扇出,发布 - 订阅,任务分发和请求 - 回复等模式连接N到N的套接字。它足够快,可以成为集群产品的结构。其异步I / O模型为您提供可扩展的多核应用程序,构建为异步消息处理任务。它有许多语言API,可在大多数操作系统上运行。 ØMQ来自iMatix,是LGPLv3开源。
使用ZMQ::SOCKET_PUB
和ZMQ::SOCKET_PULL
相同的聊天服务器可以像
$ctx = new ZMQContext();
$pub = $ctx->getSocket(ZMQ::SOCKET_PUB);
$pub->bind('tcp://*:5566');
$pull = $ctx->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://*:5567');
echo "Chat Server Start ", PHP_EOL;
while(true) {
$message = $pull->recv();
echo "Got ", $message, PHP_EOL;
$pub->send($message);
}
这可以轻松地在一个简单的系统上每分钟处理10,000
推送请求,这与您当前的服务器实现相反。
使用ZmqSocket,您可以从JavaScript代码与zmq套接字进行通信。您可以连接,发送和接收字符串消息。由于JavaScript不支持原始TCP连接,因此它使用Flash作为桥接
Simple JavaScript Bridge Example您还可以查看zmqsocket-as,它允许您通过ActionScript代码与zmq-sockets对话。