TypechoJoeTheme

轩宇网

使用php+swoole编写一个简易聊天室

Swoole:面向生产环境的 PHP 异步网络通信引擎
使 PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。使用 PHP + Swoole 作为网络通信框架,可以使企业 IT 研发团队的效率大大提升,更加专注于开发创新产品。


新建PushServer.php

<?php
/**
 * Created by PhpStorm.
 * User: zhengbingdong
 * Date: 2020/08/15
 * Time: 01:06
 */
class PushServer {
    private static $instance;
    private static $server;
    public $messageHandler;
    //处理消息的对象
    //不能够在类外面创建该对象的实例
    private function __construct() {
        //>>1.创建websocket对象
        self::$server = new swoole_websocket_server('0.0.0.0', 9502);
        //>>2.注册事件
        self::$server->on('open', [$this, 'onOpen']);
        //将当前类的onOpen方法作为open的事件处理函数
        self::$server->on('message', [$this, 'onMessage']);
        self::$server->on('close', [$this, 'onClose']);
        self::$server->on('workerStart',[$this,'onWorkerStart']);
    }
    //当客户端连上之后要执行的方法
    public function onOpen($server, $req) {
        echo "connection open: {$req->fd}\n";
    }
    //客户端向服务器发送消息要执行的方法
    public function onMessage($server, $frame) {
        //将传输的json转成数组
        $data = json_decode($frame->data,true);
        //检查方法是否存在
        if (method_exists($this->messageHandler,$data['cmd'])) {
            call_user_func([$this->messageHandler,$data['cmd']],self::$server,$data['data']);
        } else {
            $outMessage = json_encode([
                            'status' => 'error',
                            'msg' => '非法操作'
                        ]);
            echo $outMessage."\n";
            self::$server->push($frame->fd, $outMessage);
        }
    }
    //客户端和服务器端断开连接时执行的方法
    public function onClose($server,$fd) {
        $online = [];
        foreach ($server->connections as $clientId) {
            array_push($online, $clientId);
            $outMessage = json_encode(
                            [
                                'type' => 'close',
                                'fid' => $clientId,
                                'online' => $online,
                                'num' => count($server->connections)
                            ]
                        );
            self::$server->push($clientId, $outMessage);
        }
        echo "当前服务器共有 " . count($server->connections) . " 个连接\n";
        echo '客户端或服务器断开连接'.$fd."\n";
    }
    //服务器启动之后执行
    public function onWorkerStart() {
        echo 'onWorkerStart----------'.date('Y-m-d H:i:s')."\n";
        require './MessageHandler.php';
        $this->messageHandler = new MessageHandler();
    }
    public static function getInstance() {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    public function start() {
        self::$server->start();
    }
}
PushServer::getInstance()->start();
//启动推送服务

新建MessageHandler.php

<?php
/**
 * Created by PhpStorm.
 * User: zhengbingdong
 * Date: 2020/08/15
 * Time: 01:06
 */
class MessageHandler
{
    public function join($server, $data)
{
        foreach ($server->connections as $fd) {
            $outMessage = json_encode(
                [
                    'type' => 'join',
                    'client_id' => $fd,
                    'name' => $data['name'],
                    'num' => count($server->connections)
                ]
            );
            $server->push($fd, $outMessage);
        }
    }
    public function sendMessage($server, $data){
        foreach ($server->connections as $fd) {
            $outMessage = json_encode(
                [
                    'name' => $data['name'],
                    'content' => $data['content']
                ]
            );
            $server->push($fd, $outMessage);
        }
    }
    public function changeNickName($server, $data){
        foreach ($server->connections as $fd) {
            $outMessage = json_encode(
                [
                    'type' => 'changeNickName',
                    'before' => $data['before'],
                    'after' => $data['after']
                ]
            );
            $server->push($fd, $outMessage);
        }
    }
    public function outLine(){
        echo '-------------------------离开了';
    }
}

新建聊天室页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">    
    <head>
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>
            匿名即时聊天室
        </title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js">
        </script>
    </head>
    <style type="text/css" media="all">
        body { padding: 0; margin: 0; } #online { width: 100%; margin: 0 auto;
        } #messgae { background: #eee; padding: 5px; margin-bottom: 15px; height:
        380px; overflow: scroll; } #online-num { font-size: 15px; padding-left:
        10px; } #socket { background: #f5f5f5; padding: 20px; } #name { width:
        98%; } #content { width: 98%; } #sender { width: 100%; }
    </style>    
    <body>
        <div id="online">
            <div id="messgae">
                <h3 id="title">
                    匿名聊天室
                    <span id="online-num">
                        当前在线
                        <span id="num">
                        </span>
                        人
                    </span>
                </h3>
            </div>
            <div id="socket">
                <p>
                    网名:
                    <input type="text" id="name" value="">
                </p>
                <p>
                    内容:
                    <textarea name="" id="content" rows="8" cols="40">
                    </textarea>
                </p>
                <p>
                    <input type="submit" name="" id="sender" value="发送" />
                </p>
            </div>
        </div>
        <script>
            var cookie = {
                set: function(key, val, time) { //设置cookie方法
                    var date = new Date(); //获取当前时间
                    var expiresDays = time; //将date设置为n天以后的时间
                    date.setTime(date.getTime() + expiresDays * 24 * 3600 * 1000); //格式化为cookie识别的时间
                    document.cookie = key + "=" + val + ";expires=" + date.toGMTString(); //设置cookie
                },
                get: function(key) { //获取cookie方法
                    /*获取cookie参数*/
                    var getCookie = document.cookie.replace(/[ ]/g, ""); //获取cookie,并且将获得的cookie格式化,去掉空格字符
                    var arrCookie = getCookie.split(";") //将获得的cookie以"分号"为标识 将cookie保存到arrCookie的数组中
                    var tips; //声明变量tips
                    for (var i = 0; i < arrCookie.length; i++) { //使用for循环查找cookie中的tips变量
                        var arr = arrCookie[i].split("="); //将单条cookie用"等号"为标识,将单条cookie保存为arr数组
                        if (key == arr[0]) { //匹配变量名称,其中arr[0]是指的cookie名称,如果该条变量为tips则执行判断语句中的赋值操作
                            tips = arr[1]; //将cookie的值赋给变量tips
                            break; //终止for循环遍历
                        }
                    }
                    return tips;
                },
                delete: function(key) { //删除cookie方法
                    var date = new Date(); //获取当前时间
                    date.setTime(date.getTime() - 10000); //将date设置为过去的时间
                    document.cookie = key + "=v; expires =" + date.toGMTString(); //设置cookie
                }
            };
            $(function() {
                $('#name').val(cookie.get("userNickname") ? cookie.get("userNickname") : '游客' + <?=date('YmdHis'); ? >) $('#name').blur(function() {
                    var name = $('#name').val();
                    var before = cookie.get("userNickname") ? cookie.get("userNickname") : name;
                    cookie.set("userNickname", name, 24) websocket.send('{"cmd":"changeNickName","data":{"before":"' + before + '","after":"' + name + '"}}');
                });
                var websocket = new WebSocket("ws://192.168.31.107:9502");
                websocket.onopen = function() {
                    console.log('连接上服务器');
                    var intNickName = cookie.get("userNickname") ? cookie.get("userNickname") : '游客' + <?=date('YmdHis'); ? >;
                    cookie.set("userNickname", intNickName, 24);
                    websocket.send('{"cmd":"join","data":{"name":"' + intNickName + '"}}');
                }
                websocket.onmessage = function(event) {
                    var getName = cookie.get("userNickname");
                    var data = JSON.parse(event.data);
                    //console.log(data)
                    if (data.type == 'join') {
                        $('#messgae').append('<p>系统提示:' + data.name + '加入聊天室</p>');
                        $('#num').text(data.num);
                    } else if (data.type == 'close') {
                        $('#messgae').append('<p>系统提示:' + data.fid + '离开了聊天室</p>');
                    } else if (data.type == 'changeNickName') {
                        $('#messgae').append('<p>系统提示:' + data.before + '更改了网名为《' + data.after + '》</p>');
                    } else {
                        $('#messgae').append('<p>' + data.name + ':' + data.content + '</p>');
                    }
                    goBottom();
                }
                websocket.onclose = function() {
                    console.log('断开了链接');
                }
                $('#sender').click(function() {
                    var name = $('#name').val();
                    var sendContent = $('#content').val() websocket.send('{"cmd":"sendMessage","data":{"name":"' + name + '","content":"' + sendContent + '"}}');
                    $('#content').val('');
                    goBottom();
                })
                function goBottom() {
                    var div = document.getElementById('messgae');
                    div.scrollTop = div.scrollHeight;
                }
            });
        </script>
    </body>
</html>
赞(0)