swoole创建多人多房间聊天室三

        在上一个例子中,实现了多房间的多人聊天,这次这个聊天室有所改变,需要做到类似微信或QQ那样(app,pc同时使用),多个端口登入,保证数据的同时传递,考虑了很久,最好的办法就是在之前代码的基础上,再加一层redis的关系,结构脑图如下:

        

        简单点说也就是group->房间room_id->uid->fd,因为全是键值对的关系,所以我这里为了好区分全部用的是redis集合;


        代码如下:


<?php

namespace app\common;
require_once 'Predis.php';
require_once 'Task.php';
/**
*    socket面向对象的编译
*/
class Http
{
    CONST HOST='0.0.0.0';
    CONST PORT='9501';
    public $ws=null;
    public $http_server=null;
    private $key='paiv3@$))(';
    private $prefix='paiv3_';

    public function __construct()
    {   
        $this->ws=new \swoole_websocket_server(self::HOST,self::PORT);
        $this->ws->set([
            //心跳检测
            // 'heartbeat_check_interval' => 5,
            // 'heartbeat_idle_time' => 10,
        ]);
        //监听新端口
        $this->http_server=$this->ws->listen("0.0.0.0", 9502, SWOOLE_SOCK_TCP);
        //开启http模式
        $this->http_server->set([
            'open_http_protocol' => true,
        ]);

        $this->ws->on("start", [$this, 'onStart']);
        $this->http_server->on("request", [$this, 'onRequest']);
        $this->ws->on('message',[$this,'onmessage']);
        $this->ws->on('close',[$this,'onclose']);
        $this->http_server->on('close',[$this,'oncloses']);
        $this->ws->start();
    }
    //监听数据接收事件
    public function onRequest($request, $response)
    {
        //获取全部的参数
        $da=$request->post;
        //转译utf8
        foreach ($da as $k => $v) {
            $data[$k]=urldecode($v);
        }
        //判断权限
        if ($data['key'] != $this->key) {
            $response->end(json_encode(['code'=>400,'message'=>"您暂无权限访问接口",'data'=>null]));
        }else{
            //判断类型
            if ($data['type'] == 'start') {
                //开始拍卖
                //记录最新价格
                Predis::getInstance()->hset('new_price',$data['room_id'],$data['new_price']);
                //组装数据
                $arr['number']=Predis::getInstance()->scard('room_id'.$data['room_id']);
                $arr['type']="start";
                self::push_room($data['room_id'],$arr);
                $response->end(json_encode(['code'=>200,'message'=>"推送成功",'data'=>null]));
            }elseif ($data['type'] == 'change') {
                //出价成功
                //组装数据
                $arr['name']=$data['name'];
                $arr['price']=$data['price'];
                $arr['type']="change";
                //记录最新出价
                Predis::getInstance()->hset('new_price',$data['room_id'],$data['price']);
                self::push_room($data['room_id'],$arr);
                $response->end(json_encode(['code'=>200,'message'=>"推送成功",'data'=>null]));
            }elseif ($data['type'] == 'stop') {
                //暂停拍卖
                $arr['msg']=$data['msg'];
                $arr['type']="stop";
                self::push_room($data['room_id'],$arr);
                $response->end(json_encode(['code'=>200,'message'=>"推送成功",'data'=>null]));
            }elseif ($data['type'] == 'end') {
                //拍卖结束
                $arr['name']=$data['name'];
                $arr['price']=$data['price'];
                $arr['type']="end";
                self::push_room($data['room_id'],$arr);
                //删除对应的房间缓存
                //获取该房间下的用户
                    // 1) "paiv3_room_id1"
                    // 2) "paiv3_fd1"
                    // 3) "paiv3_room_id1_12"
                    // 3) "paiv3_room_id1_13"
                    // 3) "paiv3_room_id1_14"
                    // 4) "paiv3_group"
                $push_arr=Predis::getInstance()->smembers('room_id'.$data['room_id']);
                //获取该房间下用户的fd
                $fds=[];
                foreach ($push_arr as $v) {
                    $fds=Predis::getInstance()->smembers(substr($v,6));     //smembers自动写入,所以要截取掉
                    foreach ($fds as $vv) {
                        Predis::getInstance()->del(substr($vv,6));                       //删除在线的fd字符
                    }
                    Predis::getInstance()->del(substr($v,6));                       //删除在线的用户
                }
                Predis::getInstance()->del('room_id'.$data['room_id']);              //对应的价格
                Predis::getInstance()->hdel('new_price',$data['room_id']);              //对应的价格
                $response->end(json_encode(['code'=>200,'message'=>"推送成功",'data'=>null]));
            }
        }
    }
    /**
    *   $room_id    当前房间id    
    *   $arr    组装数据
    */
    public function push_room($room_id,$arr)
    {
        //获取该房间下的用户
        $push_arr=Predis::getInstance()->smembers('room_id'.$room_id);
        //获取该房间下用户的fd
        $fds=[];
        foreach ($push_arr as $k => $v) {
            $fds=Predis::getInstance()->smembers(substr($v,6));     //smembers自动写入,所以要截取掉
            foreach ($fds as $vv) {
                //推送
                $this->ws->push(substr($vv,8), json_encode($arr));
            }
        }
    }
    /**
     * 设置进程名,为后续平滑重启进程
     * @param $server
     */
    public function onStart($server) {
        swoole_set_process_name("live_master");
    }      
    
    /**
        监听接收事件的回调
    */
    public function onmessage($server, $frame)
    {
        //在接收数据的时候进行推送
        $data=json_decode($frame->data,true);
        //加入组集合(集合)
        Predis::getInstance()->sadd('group',$data['room_id']);
        //加入分组(集合)
        Predis::getInstance()->sadd('room_id'.$data['room_id'],'room_id'.$data['room_id'].'_'.$data['uid']);
        //加入会员fd的集合(集合)
        Predis::getInstance()->sadd('room_id'.$data['room_id'].'_'.$data['uid'],'fd'.$frame->fd);
        //创建fd的json数据(字符)
        $json['room_id']=$data['room_id'];
        $json['uid']=$data['uid'];
        Predis::getInstance()->set('fd'.$frame->fd,json_encode($json));

        //组装发送的数据
        $arr['name']=$data['name'];
        $arr['new_price']=Predis::getInstance()->hget('new_price',$data['room_id']);
        $arr['type']="join";
        $arr['number']=Predis::getInstance()->scard('room_id'.$data['room_id']);
        //推送
        self::push_room($data['room_id'],$arr);
    }
    /**
        监听关闭事件的回调
    */
    public function onclose($ser, $fd)
    {
        print_r("你好,我的{$fd}\n");
        //先获取字符fd,并得到room_id和uid
        $data=json_decode(Predis::getInstance()->get('fd'.$fd),true);
        //删除用户该次的fd
        Predis::getInstance()->srem('room_id'.$data['room_id'].'_'.$data['uid'],'fd'.$fd);
        //删除字段
        Predis::getInstance()->del('fd'.$fd);
    }
    public function oncloses($ser, $fd)
    {
        print_r("这个是http_server{$fd}\n");
    }
}

new Http();





猜你喜欢

转载自blog.csdn.net/feiwutudou/article/details/80774505