大家好,我們聊一下workerman架構,前端看了一下手冊,感覺是似懂非懂,做項目是沒有問題,感覺缺點的什麼。還好workerman的手冊是很完善和例子也很多。我就想可以通過例子來研究分析進行消化。
如果沒有看過手冊請先看一下手冊之後,再來檢視。這樣可以更好的吸收。我們先從一個簡單的例子來。
workerman用PHP編寫的Web消息推送器
首先是基于workerman開發的
基于PHPSocket.IO開發,使用websocket推送資料,當浏覽器不支援websocket時自動切換comet推送資料。
- 服務端
<?php
use Workerman\Worker;
use Workerman\WebServer;
use Workerman\Lib\Timer;
use PHPSocketIO\SocketIO;
include __DIR__ . '/vendor/autoload.php';
// 全局數組儲存uid線上資料
$uidConnectionMap = array();
// 記錄最後一次廣播的線上使用者數
$last_online_count = 0;
// 記錄最後一次廣播的線上頁面數
$last_online_page_count = 0;
/**
socket.io主要是通過事件來進行通訊互動的。
socket連接配接除了自帶的connect,message,disconnect三個事件以外,
在服務端和用戶端開發者可以自定義其它事件。
服務端和用戶端都通過emit方法觸發對端的事件。
**/
// PHPSocketIO服務
$sender_io = new SocketIO(2120);
// 用戶端發起連接配接事件時,設定連接配接socket的各種事件回調
$sender_io->on('connection', function($socket){
// 當用戶端發來登入事件時觸發
$socket->on('login', function ($uid)use($socket){
global $uidConnectionMap, $last_online_count, $last_online_page_count;
// 已經登入過了
if(isset($socket->uid)){
return;
}
// 更新對應uid的線上資料
$uid = (string)$uid;
if(!isset($uidConnectionMap[$uid]))
{
$uidConnectionMap[$uid] = 0;
}
// 這個uid有++$uidConnectionMap[$uid]個socket連接配接
++$uidConnectionMap[$uid];
// 将這個連接配接加入到uid分組,友善針對uid推送資料
$socket->join($uid);
$socket->uid = $uid;
// 更新這個socket對應頁面的線上資料
$socket->emit('update_online_count', "目前<b>{$last_online_count}</b>人線上,共打開<b>{$last_online_page_count}</b>個頁面");
});
// 當用戶端斷開連接配接是觸發(一般是關閉網頁或者跳轉重新整理導緻)
$socket->on('disconnect', function () use($socket) {
if(!isset($socket->uid))
{
return;
}
global $uidConnectionMap, $sender_io;
// 将uid的線上socket數減一
if(--$uidConnectionMap[$socket->uid] <= 0)
{
unset($uidConnectionMap[$socket->uid]);
}
});
});
// 當$sender_io啟動後監聽一個http端口,通過這個端口可以給任意uid或者所有uid推送資料
//phpsocket.io提供了workerStart事件回調,也就是當程序啟動後準備好接受用戶端連結時觸發的回調。
// 一個程序生命周期隻會觸發一次。可以在這裡設定一些全局的事情,比如開一個新的Worker端口等等。
$sender_io->on('workerStart', function(){
// 監聽一個http端口
$inner_http_worker = new Worker('http://0.0.0.0:2121');
// 當http用戶端發來資料時觸發
$inner_http_worker->onMessage = function($http_connection, $data){
global $uidConnectionMap;
$_POST = $_POST ? $_POST : $_GET;
// 推送資料的url格式 type=publish&to=uid&content=xxxx
switch(@$_POST['type']){
case 'publish':
global $sender_io;
$to = @$_POST['to'];
$_POST['content'] = htmlspecialchars(@$_POST['content']);
if($to){
// 有指定uid則向uid所在socket組發送資料
$sender_io->to($to)->emit('new_msgs', $_POST['content']);
}else{
// 否則向所有uid推送資料
$sender_io->emit('new_msgs', @$_POST['content']);
}
// http接口傳回,如果使用者離線socket傳回fail
if($to && !isset($uidConnectionMap[$to])){
return $http_connection->send('offline');
}else{
return $http_connection->send('ok');
}
}
return $http_connection->send('fail');
};
// 執行監聽
$inner_http_worker->listen();
// 一個定時器,定時向所有uid推送目前uid線上數及線上頁面數
Timer::add(1, function(){
global $uidConnectionMap, $sender_io, $last_online_count, $last_online_page_count;
$online_count_now = count($uidConnectionMap);
$online_page_count_now = array_sum($uidConnectionMap);
// 隻有在用戶端線上數變化了才廣播,減少不必要的用戶端通訊
if($last_online_count != $online_count_now || $last_online_page_count != $online_page_count_now)
{
$sender_io->emit('update_online_count', "目前<b>{$online_count_now}</b>人線上,共打開<b>{$online_page_count_now}</b>個頁面");
$last_online_count = $online_count_now;
$last_online_page_count = $online_page_count_now;
}
});
});
if(!defined('GLOBAL_START'))
{
Worker::runAll();
}
- 用戶端
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<link href="main.css" target="_blank" rel="external nofollow" rel="stylesheet" type="text/css" />
<script src='https://cdn.bootcss.com/socket.io/2.0.3/socket.io.js'></script>
<script src='//cdn.bootcss.com/jquery/1.11.3/jquery.js'></script>
<script src='/notify.js'></script>
</head>
<body>
<div class="notification sticky hide">
<p id="content"> </p>
<a class="close" href="javascript:" target="_blank" rel="external nofollow" > <img src="/icon-close.png" /></a>
</div>
<div class="wrapper">
<div style="width:850px;">
<h3>介紹:</h3>
<b>Web-msg-sender</b> 是一個web消息推送系統,基于<a rel="nofollow" href="https://github.com/walkor/phpsocket.io" target="_blank" rel="external nofollow" >PHPSocket.IO</a>開發。<br><br><br>
<h3>支援以下特性:</h3>
<ul>
<li>多浏覽器支援</li>
<li>支援針對單個使用者推送消息</li>
<li>支援向所有使用者推送消息</li>
<li>長連接配接推送(websocket或者comet),消息即時到達</li>
<li>支援線上使用者數實時統計推送(見頁腳統計)</li>
<li>支援線上頁面數實時統計推送(見頁腳統計)</li>
</ul>
<h3>測試:</h3>
目前使用者uid:<b class="uid"></b><br>
可以通過url:<a id="send_to_one" href="http://www.workerman.net:2121/?type=publish&to=1445590039000&content=%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9" target="_blank" rel="external nofollow" target="_blank"><font style="color:#91BD09">http://<font class="domain"></font>:2121?type=publish&to=<b class="uid"></b>&content=消息内容</font></a> 向目前使用者發送消息<br>
可以通過url:<a href="http://www.workerman.net:2121/?type=publish&to=&content=%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9" target="_blank" rel="external nofollow" target="_blank" id="send_to_all" ><font style="color:#91BD09">http://<font class="domain"></font>:2121?type=publish&to=&content=消息内容</font></a> 向所有線上使用者推送消息<br>
<script>
// 使用時替換成真實的uid,這裡友善示範使用時間戳
var uid = Date.parse(new Date());
$('#send_to_one').attr('href', 'http://'+document.domain+':2121/?type=publish&content=%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9&to='+uid);
$('.uid').html(uid);
$('#send_to_all').attr('href', 'http://'+document.domain+':2121/?type=publish&content=%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9');
$('.uid').html(uid);
$('.domain').html(document.domain);
</script>
</div>
<script>
//文檔加載後激活函數或方法
$(document).ready(function () {
//利用socket.io.js 把資訊發給伺服器
// 連接配接服務端
var socket = io('http://'+document.domain+':2120');
// 連接配接後登入
socket.on('connect', function(){
//emit 推送到伺服器
socket.emit('login', uid);
});
// 後端推送來消息時
socket.on('new_msgs', function(msgs){
//改變id="content" 元素的内容:
$('#content').html('收到消息:'+msgs);
//重點沒有它,是看不到顯示的
$('.notification.sticky').notify(
);
});
// 後端推送來線上資料時
socket.on('update_online_count', function(online_stat){
$('#online_box').html(online_stat);
});
});
</script>
<div id="footer">
<center id="online_box"></center>
<center><p style="font-size:11px;color:#555;"> Powered by <a href="http://www.workerman.net/web-sender" target="_blank" rel="external nofollow" target="_blank"><strong>web-msg-sender!</strong></a></p></center>
</div>
</body>
</html>
- 輸出
workerman用PHP編寫的Web消息推送器
phpsocket.io手冊 https://github.com/walkor/phpsocket.io/tree/master/docs/zh
socket.io.js手冊 https://www.w3cschool.cn/socket/socket-ulbj2eii.html