1. 程式人生 > 實用技巧 >在面試時用php+swoole編寫了一個簡易聊天室,面試官讓我明天來上班!

在面試時用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>

點關注,不迷路

好了各位,以上就是這篇文章的全部內容了,能看到這裡的人呀,都是人才。之前說過,PHP方面的技術點很多,也是因為太多了,實在是寫不過來,寫過來了大家也不會看的太多,所以我這裡把它整理成了PDF和文件,如果有需要的可以

點選進入暗號: PHP+「平臺」


更多學習內容可以訪問【對標大廠】精品PHP架構師教程目錄大全,只要你能看完保證薪資上升一個臺階(持續更新)

以上內容希望幫助到大家,很多PHPer在進階的時候總會遇到一些問題和瓶頸,業務程式碼寫多了沒有方向感,不知道該從那裡入手去提升,對此我整理了一些資料,包括但不限於:分散式架構、高可擴充套件、高效能、高併發、伺服器效能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell指令碼、Docker、微服務、Nginx等多個知識點高階進階乾貨需要的可以免費分享給大家,需要的可以加入我的 PHP技術交流群