基于Swoole实现视频弹幕功能(实战小练习)

作者: 温新

分类: 【高性能PHP】

阅读: 2292

时间: 2021-04-28 15:58:32

这篇练习记录是基于Swoole实现一个视频弹幕功能。此篇文章涵盖3个文件,一个是后端WebSocket服务器文件,一个是前端静态页面文件,另一个是js弹幕文件。

前端页面

文件:websocket.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="./canvasBarrage.js"></script>
    <title>基于Swoole实现视频弹幕功能</title>
    <style>
        .container {
            width: 700px;
            margin: 0 auto;
        }
        .canvas-barrage {
            position: absolute;
            width: 700px;
            height: 500px;
            pointer-events: none;
            z-index: 1;
        }
        .box {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
        }
        .barrage-msg {
            width: 700px;
            height: 20px;
            line-height: 20px;
            border: 1px solid gray;
            border-radius: 5px;
            padding: 6px 2px;
        }
        .barrage-btn {
            display: inline-block;
            background: pink;
            line-height: 20px;
            border-radius: 5px;
            color: rgb(146, 46, 46);
            font-size: 16px;
            border: none;
        }
    </style>

</head>
<body>
    <div class="container">
        <canvas id="canvasBarrage" class="canvas-barrage"></canvas>
        <video src="./test.mp4" width="700" height="500" id="video" controls></video>
        <div class="box">
            <input type="text" class="barrage-msg" id="msg" name="value" value="" required>
            <input type="button" class="barrage-btn" id="sendBtn" value="发送弹幕">
        </div>
    </div>

    <script>
        // 弹幕数据
        let barrageData = [{}];

        // 获取元素对象
        let canvasEle   = document.getElementById('canvasBarrage');
        let videoEle    = document.getElementById('video');

        // 实例化弹幕
        const barrage   = new CanvasBarrage(canvasEle, videoEle, {
            data:barrageData
        });

        // 实例化WebSocket对象
        const ws        = new WebSocket('ws://192.168.172.130:9506');

        // 连接
        ws.onopen = function (event) {
            if (ws.readyState == 1) {
                console.log('WebSocket 连接成功...');
            } else {
                console.log('WebSocket 连接失败...');
            }
        };

        // 接收消息
        ws.onmessage = function (evt) {
            barrage.add({
                value: evt.data,
                time: videoEle.currentTime,
                speed: 5
            });
        }

        ws.onerror = function (evt) {
            console.log('WebSocket 连接失败...');
        };

        ws.onclose = function() {
            console.log('WebSocket 连接关闭...');
        };

        let msg;
        let sendBtn = document.getElementById('sendBtn');
        // 发送弹幕
        sendBtn.onclick = function(){
            if (ws.readyState == 1) {
                msg = document.getElementById('msg').value;
                ws.send(msg);
            } else {
                alert('WebSocket 连接失败');
            }
        };
    </script>
</body>
</html>

弹幕js文件

文件:canvasBarrage.js

关于此文件,请到这个链接中获取

后端处理

文件:WebSocket.php

<?php

/**
*WebSocket服务器
**/

class WebSockerServ
{
    private $serv;

    public function __construct()
    {   
        $this->serv = new Swoole\WebSocket\Server("192.168.172.130", 9506);
     
         $this->serv->set([
			'worker_num'      => 2, //开启2个worker进程
			'max_request'     => 4, //每个worker进程 max_request设置为4次
			'task_worker_num' => 4, //开启4个task进程
			'dispatch_mode'   => 4, //数据包分发策略 - IP分配
			'daemonize'       => false, //守护进程(true/false)
         ]);
        
        $this->serv->on('Start', [$this, 'onStart']);
        $this->serv->on('Open', [$this, 'onOpen']);
        $this->serv->on("Message", [$this, 'onMessage']);
        $this->serv->on("Close", [$this, 'onClose']);
        $this->serv->on("Task", [$this, 'onTask']);
        $this->serv->on("Finish", [$this, 'onFinish']);
        
        $this->serv->start();
    }

    // 启动进程
    public function onStart($serv)
    {
        echo "onStart SWOOLE ".SWOOLE_VERSION . " 服务已启动".PHP_EOL;
    }

    // 连接
    public function onOpen($serv, $request) {
        echo "onOpen...客户端..." . $request->fd . ' 连接成功...'.PHP_EOL;

        // 投递异步任务
        $serv->task([
            'type' => 'login'
        ]);
    }

    // 异步任务
    public function onTask($serv, $task_id, $from_id, $data) {
        echo "#### onTask ####".PHP_EOL;
        echo "#{$serv->worker_id} onTask: [PID={$serv->worker_pid}]: task_id={$task_id}".PHP_EOL;
        $msg = '';
        switch ($data['type']) {
            case 'login':
                $msg = '自如初...';
                break;
            case 'speak':
                $msg = $data['msg'];
                break;
        }
        // 推送消息给客户端
        foreach ($serv->connections as $fd) {
            $connectionInfo = $serv->connection_info($fd);
            if ($connectionInfo['websocket_status'] == 3) {
                $serv->push($fd, $msg);
            }
        }
        // 任务完成
        $serv->finish($data);
    }

    public function onFinish($serv, $task_id, $data)
    {
        echo 'onFinished task ' . $task_id . '已完成' . PHP_EOL;
    }

    // 接收消息
    public function onMessage($serv, $frame)
    {
        $serv->task(['type' => 'speak', 'msg' => $frame->data]);
    }

    public function onClose($serv, $fd)
    {
        echo 'onClosed...' . $fd . '连接关闭' . PHP_EOL;
    }
}

$server = new WebSockerServ();

                                  

至此,弹幕完成

2021-04-27

请登录后再评论