PHP用Swoole的WebSocket功能编写聊天室Demo

寻技术 PHP编程 2023年09月15日 94

前提:

  1. linux环境下PHP有可用的Swoole扩展。
  2. 9501端口可访问。

后端

<?php
class Helper {
    /**
     * @function 将数组中的null值转化为空字符串
     * @param    $arr array 要转化的数组
     * @return   array
     * @other    void
     */
    public static function nullToEmptyString($arr) {
        if (! $arr) {
            return $arr;
        }

        foreach ($arr as $key => $value) {
            if (null === $value) {
                $arr[$key] = '';
            }
            if (is_array($value)) {
                $arr[$key] = static::nullToEmptyString($value);
            }
        }

        return $arr;
    }


    /**
     * @function 统一的RestFul风格的Api格式
     * @param    $code int    状态码
     * @param    $msg  string 显示的信息
     * @param    $data mixed  返回的数据
     * @return   string
     * @other    void
     */
    public static function jsonReturn($code = 0, $msg = '', $data = []) {
        header('Content-type:text/json;Charset=UTF-8');
        return json_encode([
            'code' => $code,
            'msg'  => $msg,
            'data' => $data === null ? [] : static::nullToEmptyString($data),
        ], JSON_UNESCAPED_UNICODE);
    }


    /**@function 配置人数
     * @param    $num
     * @return   bool
     */
    public static function setPersonNumber($num) {
        return file_put_contents(__DIR__ . '/personNum.txt', $num);
    }


    /**
     * @function 获取人数
     * @return   int
     */
    public static function getPersonNumber() {
        $file = __DIR__ . '/personNum.txt';
        if(! file_exists($file)) {
            return 0;
        }

        return file_get_contents($file);
    }


    /**
     * @function 发消息对外广播
     * @param    $ws  object \Swoole\WebSocket\Server
     * @param    $msg string 广播数据
     * @return   null
     */
    public static function broadcast(Swoole\WebSocket\Server $ws, $msg) {
        $fd = static::getPersonNumber();
        if($fd > 0) {
            for($i = 1; $i <= $fd; $i++) {
                $ws->push($i, $msg);
            }
        }

        return null;
    }
}


//创建WebSocket Server对象,监听0.0.0.0:9501端口。
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9501);


//监听WebSocket连接打开事件。
$ws->on('Open', function ($ws, $request) {
    $ws->nickname = '游客'. $request->fd;
    Helper::setPersonNumber($request->fd);
    Helper::broadcast($ws, Helper::jsonReturn(0, '', ['type' => 'enter', 'user' => $ws->nickname, 'content' => '']));
    return null;
});


//监听WebSocket消息事件。
$ws->on('Message', function ($ws, $frame) {
    Helper::broadcast($ws, Helper::jsonReturn(0, '', ['type' => 'say', 'user' => $ws->nickname, 'content' => htmlspecialchars($frame->data)]));
    return null;
});


//监听WebSocket连接关闭事件。
$ws->on('Close', function ($ws, $fd) {
    Helper::setPersonNumber(-- $fd);
    Helper::broadcast($ws, Helper::jsonReturn(0, '', ['type' => 'leave', 'user' => $ws->nickname, 'content' => '']));
    return null;
});


$ws->start();

前端

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>简易聊天室</title>
    <style>
        body * {font-size: 20px;width: 400px;height: 40px;}
    </style>
</head>
<body>
    <input type="text" id="text">
    <input type="button" id="send" value="发送">
    <div id="box"></div>

</body>
<script>
    //初始化
    var websocket = new WebSocket('ws://192.168.3.180:9501/swoole.php');


    //打开事件
    websocket.onopen = function (evt) {
        document.getElementById('send').onclick = function() {
            var msg = document.getElementById('text').value;
            if(msg) {
                websocket.send(msg);
            }
        }
    };


    //消息事件
    websocket.onmessage = function (evt) {
        var data = JSON.parse(evt.data);
        var data = data.data;
        if(data.type == 'enter') {
            var e = '<p style="color:green">' + data.user + '进入聊天室</p>';
        } else if(data.type == 'leave') {
            var e = '<p style="color:red">' + data.user + '离开聊天室</p>';
        } else if (data.type == 'say') {
            var e = '<p style="color:black">' + data.user + '说:' + data.content + '</p>';
        }

        var element = document.getElementById('box').innerHTML += e;
    };


    //关闭事件
    websocket.onclose = function (evt) {
        console.log("WebSocket 已断开连接");
    };


    //错误事件
    websocket.onerror = function (evt, e) {
        console.log("WebSocket 错误:" + evt.data);
    };
</script>
</html>
关闭

用微信“扫一扫”