审查视图

application/socketio/controller/Server.php 5.5 KB
何书鹏 authored
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
<?php
namespace app\socketio\controller;

use Workerman\Worker;
use Workerman\Timer;
use PHPSocketIO\SocketIO;
use Workerman\Protocols\Http\Request;
use Workerman\Connection\TcpConnection;

class Server
{
    // 全局数组保存uid在线数据
    private $uidConnectionMap = array();
    // 记录最后一次广播的在线用户数
    private $last_online_count = 0;
    // 记录最后一次广播的在线页面数
    private $last_online_page_count = 0;

    public function index(){
        header("Access-Control-Allow-Origin: *");
        // PHPSocketIO服务
何书鹏 authored
22 23
        $context = array(
            'ssl' => array(
2  
何书鹏 authored
24 25
                'local_cert'  => '/usr/local/nginx/uploads/chengyigou.cn/chengyigou.cn.crt',
                'local_pk'    => '/usr/local/nginx/cert/chengyigou.cn/chengyigou.cn.key',
何书鹏 authored
26 27 28 29
                'verify_peer' => false,
            )
        );
        $sender_io = new SocketIO(2120,$context);
何书鹏 authored
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
        // 客户端发起连接事件时,设置连接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($this->uidConnectionMap[$uid]))
                {
                    $this->uidConnectionMap[$uid] = 0;
                }
                // 这个uid有++$uidConnectionMap[$uid]个socket连接
                ++$this->uidConnectionMap[$uid];
                // 将这个连接加入到uid分组,方便针对uid推送数据
                $socket->join($uid);
                $socket->uid = $uid;
                // 更新这个socket对应页面的在线数据
                $socket->emit('update_online_count', "当前<b>{$this->last_online_count}</b>人在线,共打开<b>{$this->last_online_page_count}</b>个页面");
            });

            // 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致)
            $socket->on('disconnect', function () use($socket) {
                if(!isset($socket->uid))
                {
                    return;
                }
                // global $uidConnectionMap, $sender_io;
                // 将uid的在线socket数减一
                if(--$this->uidConnectionMap[$socket->uid] <= 0)
                {
                    unset($this->uidConnectionMap[$socket->uid]);
                }
            });
        });

        // 当$sender_io启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据
        $sender_io->on('workerStart', function() use ($sender_io) {
            // 监听一个http端口
            $inner_http_worker = new Worker('http://0.0.0.0:2121');
            // 当http客户端发来数据时触发
            $inner_http_worker->onMessage = function(TcpConnection $http_connection, Request $request) use ($sender_io) {
                // 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($this->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() use ($sender_io) {
                // global $uidConnectionMap, $sender_io, $last_online_count, $last_online_page_count;
                $online_count_now = count($this->uidConnectionMap);
                $online_page_count_now = array_sum($this->uidConnectionMap);
                // 只有在客户端在线数变化了才广播,减少不必要的客户端通讯
                if($this->last_online_count != $online_count_now || $this->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>个页面");
                    $this->last_online_count = $online_count_now;
                    $this->last_online_page_count = $online_page_count_now;
                }
            });
        });

        if(!defined('GLOBAL_START'))
        {
            Worker::runAll();
        }
    }
}