基于phpsocket.io实现的web消息通知DEMO
<?php use Workerman\Worker; use Workerman\Timer; use PHPSocketIO\SocketIO; use Workerman\Protocols\Http\Request; use Workerman\Connection\TcpConnection; include __DIR__ . '/vendor/autoload.php'; // 全局数组保存uid在线数据 $uidConnectionMap = array(); // 记录最后一次广播的在线用户数 $last_online_count = 0; // 记录最后一次广播的在线页面数 $last_online_page_count = 0; // 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推送数据 $sender_io->on('workerStart', function(){ // 监听一个http端口 $inner_http_worker = new Worker('http://0.0.0.0:2121'); // 当http客户端发来数据时触发 $inner_http_worker->onMessage = function(TcpConnection $http_connection, Request $request){ global $uidConnectionMap; $post = $request->post(); $post = $post ? $post : $request->get(); // 推送数据的url格式 type=publish&to=uid&content=xxxx switch(@$post['type']){ case 'publish': global $sender_io; $to = @$post['to']; $post['content'] = htmlspecialchars(@$post['content']); // 有指定uid则向uid所在socket组发送数据 if($to){ $sender_io->to($to)->emit('new_msg', $post['content']); // 否则向所有uid推送数据 }else{ $sender_io->emit('new_msg', @$post['content']); } // http接口返回,如果用户离线socket返回fail if($to && !isset($uidConnectionMap[$to])){ return $http_connection->send('off line'); }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(); }
web html页面:
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <link href="./main.css" rel="stylesheet" type="text/css" /> <script src='http://cdn.bootcss.com/socket.io/2.0.3/socket.io.js'></script> <script src='http://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:"> <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">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"><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" 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://127.0.0.1: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://127.0.0.1:2121/?type=publish&content=%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9'); $('.uid').html(uid); $('.domain').html('127.0.0.1'); </script> </div> <script> $(document).ready(function () { // 连接服务端 var socket = io('ws://127.0.0.1:2120'); // 连接后登录 socket.on('connect', function(){ socket.emit('login', uid); }); // 后端推送来消息时 socket.on('new_msg', function(msg){ $('#content').html('收到消息:'+msg); $('.notification.sticky').notify(); }); // 后端推送来在线数据时 socket.on('update_online_count', function(online_stat){ console.log(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"><strong>web-msg-sender!</strong></a></p></center> </div> </body> </html>
代码附件下载地址:点我下载
滴水成冰,世间不存在毫无意义的付出,时间终会给你答案。