用workerman做的http服務(wù)器,如果用作長輪詢的話如何能不造成阻塞呢?
這個是一個長輪訓(xùn)demo
use Workerman\Worker;
require_once './Workerman/Autoloader.php';
// 初始化一個worker容器,監(jiān)聽1234端口
$worker = new Worker('http://0.0.0.0:1234');
$worker->count = 1;
// 初始化一個數(shù)組,用來保存所有的長輪訓(xùn)連接
$poll_connections = array();
/*
* 當(dāng)有客戶端發(fā)來消息時
* 長輪訓(xùn)拉取數(shù)據(jù)url格式為 http://xxxx:1234/?type=get&uid=xxx
* 向某uid發(fā)送數(shù)據(jù)格url格式 http://xxxx:1234/?type=send&to_uid=xxx&content=xxx
*/
$worker->onMessage = function($connection, $data)
{
global $poll_connections;
if(empty($_GET))
{
return $connection->close('type empty');
}
// 這個請求是長輪訓(xùn)活取數(shù)據(jù)請求
if($_GET === 'get')
{
// 這里簡單的用uid驗(yàn)證用戶身份,沒傳uid視為非法請求
if(!isset($_GET))
{
return $connection->close('empty uid');
}
// 臨時給當(dāng)前的連接對象添加一個屬性保存uid
$connection->uid = $_GET;
// 保存客戶端的連接對象,當(dāng)需要向這個uid推送數(shù)據(jù)時需要使用這個對象
$poll_connections = $connection;
// 重點(diǎn)是這里,不send任何數(shù)據(jù),則會和瀏覽器一直保持連接
return;
}
// 這個請求是向某個uid長輪訓(xùn)推送數(shù)據(jù)
elseif($_GET === 'send')
{
// 檢查參數(shù)是否都傳了
if(!isset($_GET) || !isset($_GET))
{
return $connection->close('to_uid or content empty');
}
// 查找to_uid 對應(yīng)的連接對象,以便向to_uid的瀏覽器發(fā)送數(shù)據(jù)
if(!isset($poll_connections))
{
// to_uid 不在線,發(fā)送不在線提示
return $connection->close("uid:{$_GET} offline");
}
// 注意這里,向to_uid的瀏覽器發(fā)送了數(shù)據(jù)
$poll_connections->close($_GET);
// 給發(fā)送者返回成功提示
$connection->close("send success!");
return;
}
// type傳的不對,非法請求
else
{
return $connection->close('unknown type :' . $_GET);
}
};
// 當(dāng)有客戶端連接斷開時,刪除uid到連接對象的映射
$worker->onClose = function($connection)
{
global $poll_connections;
if(isset($connection->uid))
{
unset($poll_connections);
}
};
// 運(yùn)行所有的worker(其實(shí)當(dāng)前只定義了一個)
Worker::runAll();
在線測試
長輪詢接受url
http://workerman.net:1234/?type=get&uid=123
http://workerman.net:1234/?type=get&uid=456
http://workerman.net:1234/?type=get&uid=789
...
發(fā)送消息url
http://workerman.net:1234/?type=send&to_uid=123&content=hello
http://workerman.net:1234/?type=send&to_uid=456&content=hello
...
技巧是不向?yàn)g覽器send數(shù)據(jù),瀏覽器就會一直等待數(shù)據(jù),然后服務(wù)端業(yè)務(wù)該干嘛干嘛,服務(wù)端不會阻塞,等需要發(fā)送數(shù)據(jù)時,在向?yàn)g覽器send。
這樣一個worker進(jìn)程就能維持大量的連接(上萬或者數(shù)十萬),服務(wù)端是非阻塞的,性能很高,服務(wù)器也不會有任何負(fù)載