workerman用PHP编写的Web消息推送器

大家好,我们聊一下workerman框架,前端看了一下手册,感觉是似懂非懂,做项目是没有问题,感觉缺点的什么。还好workerman的手册是很完善和例子也很多。我就想可以通过例子来研究分析进行消化。

如果没有看过手册请先看一下手册之后,再来查看。这样可以更好的吸收。我们先从一个简单的例子来。
workerman用PHP编写的Web消息推送器
首先是基于workerman开发的
基于PHPSocket.IO开发,使用websocket推送数据,当浏览器不支持websocket时自动切换comet推送数据。

  1. 服务端
<?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();
}

  1. 客户端
<!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='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:"> <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://'+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"><strong>web-msg-sender!</strong></a></p></center>
</div>
</body>
</html>

  1. 输出
    在这里插入图片描述

在这里插入图片描述

phpsocket.io手册 https://github.com/walkor/phpsocket.io/tree/master/docs/zh
socket.io.js手册 https://www.w3cschool.cn/socket/socket-ulbj2eii.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值