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

这次写的不依赖框架,不用nginx配置,只是依靠swoole的http_server和websocket,也是用的多端口监听,一边实现了web端的访问,一边实现了socket的发送;

    文档在这里,可以多认真的读一下:https://wiki.swoole.com/wiki/page/525.html

好的,直接上码;


http.php

<?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;

    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)
    {
        //获取全部的参数
        $data=$request->get;
        //判断类型
       if ($data['type'] == 'start') {
            //开始拍卖
            //组装数据
            $arr['number']=count(Predis::getInstance()->hgetall($data['room_id']))-1;
            $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";
            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);
            //删除对应的房间
            Predis::getInstance()->del($data['room_id']);
            Predis::getInstance()->srem('group',$data['room_id']);
            $response->end(json_encode(['code'=>200,'message'=>"推送成功",'data'=>null]));
        }
    }
    /**
    *   $room_id    当前房间id    
    *   $arr    组装数据
    */
    public function push_room($room_id,$arr)
    {
        //获取在线用户的fd
        $push_arr=Predis::getInstance()->hvals($room_id);
        //推送
        foreach ($push_arr as $v) {
            $this->ws->push($v, 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()->hset($data['room_id'],$data['uid'],$frame->fd);
        //加入组集合
        Predis::getInstance()->sadd('group',$data['room_id']);
        //组装数据
        $arr['name']=$data['name'];
        $arr['type']="join";
        $arr['number']=count(Predis::getInstance()->hgetall($data['room_id']));
        //推送
        self::push_room($data['room_id'],$arr);
    }
    /**
        监听关闭事件的回调
    */
    public function onclose($ser, $fd)
    {
        print_r("你好,我的{$fd}\n");
        //退出并删除多余的分组fd
        $group=Predis::getInstance()->sMembers('group');
        foreach ($group as $v) {
            $fangjian=Predis::getInstance()->hgetall($v);
            foreach ($fangjian as $k => $vv) {
                if ($fd == $vv) {
                    Predis::getInstance()->hdel($v,$k);
                }
            }
        }
    }
    public function oncloses($ser, $fd)
    {
        print_r("这个是http_server{$fd}\n");
    }
}

new Http();

用户打开页面后我直接用socket的Onpen事件,所以这里就不用再写用户加入的判断逻辑了

index.html


<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>我是来测试的</title>
</head>
<body>
<h1>0</h1>
<script type="text/javascript">
	//连接服务
	var wsServer = 'wss://code.77wx.cn:9503';
	//实例化
	var websocket = new WebSocket(wsServer);

	//监听开启事件(只负责监听,没有实际的开启作用)
	websocket.onopen = function (evt) {
		var data={
			room_id:1,
			uid:'a',
			name:'夜袭寡妇村',
		};
		websocket.send(JSON.stringify(data));
	};
    function log(msg){
    	console.log(msg);
    }
	//消息
	websocket.onmessage = function (evt) {
		//监听消息后,直接给服务器传递消息
	    var e = JSON.parse(evt.data);
	    switch(e.type){
	    	//进入房间
			case "join":
			log("用户进入房间,当前人数:"+e.num);
			alert("用户 "+e.name+" 进入房间,当前人数:"+e.number);
			break;
			//开始拍卖
			case "start":
				log('拍卖开始,当前有'+e.number+'人和您同时竞拍!');
				alert('拍卖开始,当前有'+e.number+'人和您同时竞拍!');
			break;
			//用户出价
			case "change":
			   log("用户"+e.name+"出价:"+e.price+"元");
			   alert("用户 "+e.name+" 出价:"+e.price+"元");
			break; 
			//活动结束
			case "end":
				alert("用户 "+e.name+" 以:"+e.price+"元,获得竞拍大奖");
				log("用户 "+e.name+" 以:"+e.price+"元,获得竞拍大奖");
			break;

	    }
	    console.log('来自server的最新消息: ' + evt.data);
	};
	//关闭事件
	websocket.onclose = function (evt) {
		console.log("我关闭了html");
	};
	//报错
	websocket.onerror = function (evt, e) {
	    console.log('Error occured: ' + evt.data);
	};
</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/feiwutudou/article/details/80762327
今日推荐