PHP-Swoole+websocket制作实时弹幕

一、PHP下的Swoole模块安装

安装的话去官网 -> https://www.swoole.com/ 根据提示一步一步操作即可

二、弹幕的实现

好了,看到这就代表已经安装好了 Swoole,那就来简单说一下下弹幕的实现

额 其实弹幕实现的话有一个现成的哦,叫做,,(等下我想想) Jquery_danmujs是叫这个吧,嗯, https://github.com/chiruom/jquery.danmu.js 放上链接 下载就行了

三、Swoole的消息传输

弹幕嘛 就可以给他看作多个人的聊天室,这里的话后台就用到Swoole,前台webscoket

四、代码

貌似也没什么说的直接写代码吧,前端播放视频我用的是video-js

<?php

    /*
     *  --创建socket连接
     *
     * 
     * */
    class ws_server{

        public $live_id = null; //获取直播间id
        public $fd = null; //获取用户fd
        public $redis_fd = null; //储存用户分类fd用户分类用户

        public function __construct(){
            $this->server();
        }

        public function server(){
            $server = new swoole_websocket_server("0.0.0.0",9502); //定义swoole链接

            //设置 swoole进程数以及日志目录
            $server -> set([
               'worker_num' => 5, //设置进程数为5
                'daemonize' => true, //设置为守护进程-这样会在后台运行
                'log_file' => __DIR__ . '/swoolelog.log', //设置日志目录
            ]);

            $server -> on("open",function ($server,$request){
               //var_dump($request);
               $live_id = $request -> server["query_string"];
               $this->live_id = substr($live_id,stripos($live_id,"=")+1); //获取直播id
               $msg = '{ "text":"Master welcome","color":"undefined","size":1,"position":"0"'; //这里json格式不要写完因为要做实时的就得留一个时间让客户端加上去

                echo date("Y-m-d:H:i:s")." - ".$request -> fd.PHP_EOL;
               $server -> push($request->fd,$msg); //加入房间时发送提示
               $this->fd = $request -> fd;
               $this->redis_model(1,$server); //将用户的fd 存入redis列表
            });

            $server -> on('message',function ($server,$request){
                foreach ($this->redis_fd as $key => $value){ //循环查询redis所存用户数据 并发送内容
                    $server -> push($value,$request -> data);
                }
            });

            $server -> on('close',function ($server,$request){
                $this->redis_model(2,$server); //用户退出时将 用户fd剔除redis列表
                echo date("Y-m-d:H:i:s")."-".$this -> fd.PHP_EOL;
            });
            $server -> start(); //开启进程(服务)
        }

        public function redis_model($model,$server)
        {
            $redis = new Redis();

            $redis -> connect("127.0.0.1",6379); //创建redis连接

            if($redis -> ping()){
                if($model == 1){
                    if($this->fd != null && $this->live_id != null){
                        $this->redis_fd = $redis -> lRange($this->live_id,0,-1);
                        if(!empty($this->redis_fd)){ //如果redis列表存在既要判断列表内是否存在该值
                            if(!in_array($this->fd,$this->redis_fd)){
                                $redis -> rPushx($this->live_id,$this->fd);
                            }
                        }else{
                            $redis -> lPush($this->live_id,$this->fd);
                        }
                        $this->redis_fd = $redis -> lRange($this->live_id,0,-1);
                    }else{
                        $server -> push($this->fd,'{ "text":"连接服务器失败","color":"undefined","size":"1","position":"0"');
                    }
                }else if($model == 2){
                    $redis -> lRem($this->live_id, $this->fd, 0); //将用户剔除redis列表
                }
            }else{
                $server -> push($this->fd,'{ "text":"连接服务器失败","color":"undefined","size":"1","position":"0"');
                echo "redis_error!".PHP_EOL;
            }
        }

    }

    new ws_server();

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport"    content="width=device-width, initial-scale=1.0">
    <title>弹幕made by diligentyang</title>
    <style>
        body {
            font-family: "Microsoft YaHei" ! important;
            font-color:#222;
        }
        pre {
            line-height: 2em;
            font-family: "Microsoft YaHei" ! important;
        }
        h4 {
            line-height: 2em;
        }
        #danmuarea {
            position: relative;
            background: #222;
            width:800px;
            height: 445px;
            margin-left: auto;
            margin-right: auto;
        }
        .center {
            text-align: center;
        }
        .ctr {
            font-size: 1em;
            line-height: 2em;
        }
    </style>
    <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
    <script src="../dist/jquery.danmu.min.js"></script>
</head>

<body class="center">
Demo<br><br>
<!--黑背景和弹幕区-->
<div id="danmuarea">
    <div id="danmu" >
    </div>
</div>
<!--控制区-->
<div class="ctr" >
    <button type="button"  onclick="pauser()">弹幕暂停</button>      
    <button type="button"  onclick="resumer() ">弹幕继续</button>    
    显示弹幕:<input type='checkbox' checked='checked' id='ishide' value='is' onchange='changehide()'>     
    弹幕透明度:
    <input type="range" name="op" id="op" onchange="op()" value="100"> <br>
    当前弹幕运行时间(秒):<span id="time"></span>  
    <!--设置当前弹幕时间(秒): <input type="text" id="set_time" max=20 />
    <button type="button"  onclick="settime()">设置</button>-->
    <br>
    发弹幕:
    <select  name="color" id="color" >
        <option value="white">白色</option>
        <option value="red">红色</option>
        <option value="green">绿色</option>
        <option value="blue">蓝色</option>
        <option value="yellow">黄色</option>
    </select>
    <select name="size" id="text_size" >
        <option value="1">大文字</option>
        <option value="0">小文字</option>
    </select>
    <select name="position" id="position"   >
        <option value="0">滚动</option>
        <option value="1">顶端</option>
        <option value="2">底端</option>
    </select>
    <input type="textarea" id="text" max=300 />
    <button type="button"  onclick="send()">发送</button>
</div>
<script>
    //WebSocket
    const websocket= new WebSocket('你的ws服务端地址');

    websocket.onopen = function (evt) {
        console.log("Connected to WebSocket server.");
        //连上之后就打开弹幕
        $('#danmu').danmu('danmuResume');
    };

    websocket.onclose = function (evt) {
        console.log("Disconnected");
    };

    websocket.onmessage = function (evt) {
          var time = $('#danmu').data("nowTime")+1;
          var text_obj= event.data +',"time":'+time+'}';//上面说到json并没有写完要预留一个时间,这里加上去就行了
          console.log(text_obj);
          var new_obj=eval('('+text_obj+')');
          $('#danmu').danmu("addDanmu",new_obj);//添加弹幕
    };

    websocket.onerror = function (evt, e) {
        console.log('Error occured: ' + evt.data);
    };



    //初始化
    $("#danmu").danmu({
        left:0,
        top:0,
        height:"100%",
        width:"100%",
        speed:20000,
        opacity:1,
        font_size_small:16,
        font_size_big:24,
        top_botton_danmu_time:6000
    });
    //一个定时器,监视弹幕时间并更新到页面上
    function timedCount(){
        $("#time").text($('#danmu').data("nowTime"));

        t=setTimeout("timedCount()",50)

    }
    timedCount();


    function starter(){
        $('#danmu').danmu('danmuStart');
    }
    function pauser(){
        $('#danmu').danmu('danmuPause');
    }
    function resumer(){
        $('#danmu').danmu('danmuResume');
    }
    function stoper(){
        $('#danmu').danmu('danmuStop');
    }
    function getime(){
        alert($('#danmu').data("nowTime"));
    }
    function getpaused(){
        alert($('#danmu').data("paused"));
    }

    //发送弹幕,使用了文档README.md第7节中推荐的方法
    function send(){
        var text = document.getElementById('text').value;
        var color = document.getElementById('color').value;
        var position = document.getElementById('position').value;
        var size =document.getElementById('text_size').value;
        var text_obj='{ "text":"'+text+'","color":"'+color+'","size":"'+size+'","position":"'+position+'"';
        //利用websocket发送
        websocket.send(text_obj);
        //清空相应的内容
        document.getElementById('text').value='';
    }
    //调整透明度函数
    function op(){
        var op=document.getElementById('op').value;
        $('#danmu').danmu("setOpacity",op/100);
    }

    //调隐藏 显示
    function changehide() {
        var op = document.getElementById('op').value;
        op = op / 100;
        if (document.getElementById("ishide").checked) {
            $("#danmu").danmu("setOpacity",1)
        } else {
            $("#danmu").danmu("setOpacity",0)

        }
    }

    //设置弹幕时间
    function settime(){
        var t=document.getElementById("set_time").value;
        t=parseInt(t)
        $('#danmu').danmu("setTime",t);
    }
</script>

</body>
</html>

html的话我就只写弹幕层了因为我比较懒

最后附上demo链接 http://www.o4d.cn/live/1.html

点赞

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注