swoole實驗版聊天室

  「swoole實驗版聊天室」是依據一堂swoole培訓課內容改編的,結合了bootstrap前端框架、redis數據庫、jquery框架等實現基本功能,只是體現了swoole的應用,並非爲了專門寫個聊天室。php


  本程序開發環境:
  1.ubuntu16.04.1
  2.PHP Version 7.2.21
  3.swoole Version 4.4.3
  4.Redis Version 4.0.2
  安裝步驟(略)。
  效果以下:css

代碼以下:html

index.php文件前端

<!DOCTYPE html>
<html>
    <head>
        <title>swoole實驗版聊天室</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta http-equiv="cache-control" content="no-cache">
        <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/css/bootstrap.min.css">
        <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://cdn.staticfile.org/popper.js/1.12.5/umd/popper.min.js"></script>
        <script src="https://cdn.staticfile.org/twitter-bootstrap/4.1.0/js/bootstrap.min.js"></script>
        <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">

        <style>
            body{background-color: #191970;}
            @media screen and (min-width: 992px) {
                    div{display: none}
                    body {background: #fff}
                    body:before {
                        content: "不支持此設備瀏覽!";
                        position: absolute;
                        left: 10px;
                        top: 30px
                 }
             }
             
            @media screen and (min-width: 768px) and (max-width: 991px) {
                    div{display: none}
                    body {background: #fff}
                    body:before {
                        content: "不支持此設備瀏覽!";
                        position: absolute;
                        left: 10px;
                        top: 30px
                 }
             }
             
            @media screen and (min-width: 576px) and (max-width: 767px) {
                #result{
                    width: 100%; 
                    height: 300px; 
                    overflow-y: scroll;
                    margin: 0px;
                    padding: 5px;
                 }
                 #is-open{
                     display: inline-block;
                     border: solid 1px #dcdcdc;
                     padding: 6px;
                     margin: 6px 0px;
                     border-radius: 8px;
                     color: #fff;
                 }
                 .ms {
                     display:inline-block;
                     width:80%
                 }
                 .msl {
                     display:inline-block;
                     width:40%;
                     background-color: #66cdaa
                 }
                 .btn {
                     display:inline-block;
                     float: right;
                     width:20%
                 }
                 .mess{
                     color: #00fa9a;
                     text-align: right
                 }
                 .mess-1{
                     display: inline-block;
                     word-wrap:break-word;
                     word-break:break-all;
                     color: #2f4f4f;
                     background-color:#f4a460;
                     padding: 8px;
                     border-radius: 8px;
                     text-align: left
                 }
                 .mess-1-1, .mess-2-2 {
                      display: inline-block;
                      color: #000;
                      font-weight: bold;
                      background-color: #add8e6;
                  }
                  .mess-1-1{
                      padding: 8px;
                      border-radius: 8px
                  }
                  .mess-2-2{
                      padding: 8px;
                      border-radius: 8px
                  }
                 .mess-2{
                     display: inline-block;
                     word-wrap:break-word;
                     word-break:break-all;
                     color: #696969;
                     background-color:#fff;
                     padding: 8px;
                     border-radius: 8px
                 }
                 .tot{
                     display: inline-block;
                     width: 40%;
                     word-wrap:break-word;
                     word-break:break-all;
                     color: #fff;
                     float: right;
                     margin-top: 3px;
                 }
                 .bottom-box{
                     position: fixed;
                     left: 0px;
                     bottom: 0px;
                     width:100%;
                     background-color: #191970;
                     padding-top: 10px
                  }
              }
              
            @media screen and (min-width: 300px) and (max-width: 575px) {
                #result{
                    width: 100%; 
                    height: 300px; 
                    overflow-y: scroll;
                    margin: 0px;
                    padding: 5px;
                 }
                 #is-open{
                     display: inline-block;
                     border: solid 1px #dcdcdc;
                     padding: 6px;
                     margin: 6px 0px;
                     border-radius: 8px;
                     color: #fff;
                 }
                 .ms {
                     display:inline-block;
                     width:80%
                 }
                 .msl {
                     display:inline-block;
                     width:40%;
                     background-color: #66cdaa
                 }
                 .btn {
                     display:inline-block;
                     float: right;
                     width:20%
                 }
                 .mess{
                     color: #00fa9a;
                     text-align: right
                 }
                 .mess-1{
                     display: inline-block;
                     word-wrap:break-word;
                     word-break:break-all;
                     color: #2f4f4f;
                     background-color:#f4a460;
                     padding: 8px;
                     border-radius: 8px;
                     text-align: left
                 }
                 .mess-1-1, .mess-2-2 {
                      display: inline-block;
                      color: #000;
                      font-weight: bold;
                      background-color: #add8e6;
                  }
                  .mess-1-1{
                      padding: 8px;
                      border-radius: 8px
                  }
                  .mess-2-2{
                      padding: 8px;
                      border-radius: 8px
                  }
                 .mess-2{
                     display: inline-block;
                     word-wrap:break-word;
                     word-break:break-all;
                     color: #696969;
                     background-color:#fff;
                     padding: 8px;
                     border-radius: 8px
                 }
                 .tot{
                     display: inline-block;
                     width: 40%;
                     word-wrap:break-word;
                     word-break:break-all;
                     color: #fff;
                     float: right;
                     margin-top: 3px;
                 }
                 .bottom-box{
                     position: fixed;
                     left: 0px;
                     bottom: 0px;
                     width:100%;
                     background-color: #191970;
                     padding-top: 10px
                  }
              }
        </style>
        
    </head>
    <body>
        <div class="container">
            <span id="is-open">服務器正在鏈接......</span>
            <span class="tot">當前共有<span id="total">0</span>個窗口在鏈接!</span>
            <p id="result"></p>
            
            <form>
                <div class = "bottom-box">
                    <p><span style="color: #fff">暱稱:</span><input type="text" id="username"  class="form-control msl"/></p>
                    <p>
                        <input id="message" class="form-control ms">
                        <button id="btn" type="button" class="btn btn-primary">發送</button>
                    </p>
                </div>
            </form>

        </div>
        
<script>
    $(document).ready(function(){
        
        var timeOut;
        var arrResult = [];
        
        // 設置cookie函數
        function setCookie(cname,cvalue,exdays){
            var d = new Date();
            d.setTime(d.getTime()+(exdays*24*60*60*1000));
            var expires = "expires="+d.toGMTString();
            document.cookie = cname + "=" + cvalue + "; " + expires;
        }

        // 取出cookie數據函數
        function getCookie(cname){
            var name = cname + "=";
            var ca = document.cookie.split(';');
            for(var i=0; i<ca.length; i++) {
                var c = ca[i].trim();
                if (c.indexOf(name)==0) return c.substring(name.length,c.length);
            }
            return "";
        }
    
/* 刷新頁面時從取出數據初始化頁面 */
    
        // 初始化插入暱稱
        var usrName = (getCookie("userName") != null)?getCookie("userName"):"";
        $("#username").val(usrName);
        
        setTimeout(function(){
            // 初始化滾動消息到最新
            $("#result").scrollTop(result.scrollHeight);
        },500);
    
        
        // 刷新頁面時從redis數據庫取出數據初始化頁面
        $.post("./ajax.php",{},function(ajaxData){
            var m = JSON.parse(ajaxData);
            for(key in m){
                arrResult.push(m[key]);
            }
            $("#result").html(arrResult.join(''));
        });
        
/* 初始化數據結束 */
    
/* websocket通訊 */
        var ws = new WebSocket("ws://47.94.224.241:9503");
    
        ws.onopen=function(){
            $("#is-open").html('服務器鏈接成功......');
            clearInterval(timeOut);
        }
    
        ws.onmessage=function(res){
            var data=JSON.parse(res.data);
            if(data.userId){
                window.userId = data.userId;
            }

            if(data.total){
                $("#total").html(data.total);
                return false;
            }
        
            if( data.cookieUsrName == getCookie("userName") ) {
                arrResult.push('<p class="mess"><span class="mess-1">' + data.message + '</span><span class="mess-1-1">我</span></p>');
            }else{
                arrResult.push('<p><span class="mess-2-2">' + data.username + '</span><span class="mess-2">' + data.message + '</span></p>');
            }

            // while()裏的49要與ajax.php裏的lpush方法裏的參數49要統一
            while ( arrResult.length > 49) {
                arrResult.shift();
            }
            
            // 顯示在界面上
            var val = arrResult.join("");
            $("#result").html(val);

            $("#result").scrollTop(result.scrollHeight);
        }

        ws.onclose=function(){
            $("#is-open").html('');
            $("#is-open").html('服務器已斷開......');
            
            // 斷開鏈接刷新頁面
            timeOut = setInterval(function(){
                location.replace(location.href);
            }, 1000);
        }

        btn.onclick=function(){
            if($("#username").val() == '' || $("#message").val() == '') {
               
                // 打開模態框
                $('#myModal').modal('show');
            }else{
                
               /*
                 * 組裝數據,數據是在js裏組裝的,swoole服務器只是轉發了一下數據並存入redis數據庫
                 *
                 * 判斷「我」的方法:
                 * 1. 一種是判斷fromuserid,能夠判斷到具體窗口,一個瀏覽器打開3個窗口就是3個不一樣的「我」;
                 * 2. 另外一種是判斷cookie或session裏存儲的用戶名,即cookieUsrName鍵,一個瀏覽器認
                 *     爲是一個用戶,這裏是用暱稱代替了。
                 */
                var data={ fromuserid: window.userId, username: username.value, message: message.value, cookieUsrName: getCookie("userName") } ;
               
                //對象轉JSON字符串發送到服務器
                ws.send( JSON.stringify(data) );
                message.value='';
           }
        }
    
        username.onkeyup = function() {
               //暱稱存入cookie
               setCookie("userName", $("#username").val(), 7);
        }
    });
</script>

<!-- 模態框 -->
<div class="modal fade" id="myModal">
  <div class="modal-dialog">
    <div class="modal-content">
 
      <!-- 模態框頭部 -->
      <div class="modal-header">
        <h4 class="modal-title">
            <i class="fa fa-exclamation-circle fa-lg" style="color: red"></i>
            錯誤提示:
        </h4>
        <button type="button" class="close" data-dismiss="modal">&times;</button>
      </div>
 
      <!-- 模態框主體 -->
      <div class="modal-body">
        「暱稱」和「消息」內容都不容許爲空,請從新輸入!
      </div>
 
      <!-- 模態框底部 -->
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">關閉</button>
      </div>
      
      </div>
  </div>
</div>

</body>
</html>

 

 

swooleServer.phpreact

<?php
$ws = new swoole_websocket_server("0.0.0.0", 9503, SWOOLE_PROCESS);

$ws->set(array(
    'reactor_num' => 2, //reactor thread num
    'worker_num' => 4,    //worker process num
    'backlog' => 128,   //listen backlog
    'max_conn' => 10000, 
    'max_request' => 50,
    'dispatch_mode' => 1,
    'daemonize' => 1
));

$ws->on('open', function ($ws, $request) {
    
    $tot = count($ws->connections);
    $ws->push($request->fd, json_encode(['userId' => $request->fd, 'total' => $tot]));
    
});

$ws->on('message', function ($ws, $frame) {
    // 每一個用戶發送的消息向全部用戶轉發
    foreach($ws->connections as $value) {
        $ws->push($value, $frame->data);
    }

// 向redis數據庫寫入數據,數據類型「列表」
$redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->lpush("messages", $frame->data); // 超過100條數據開始刪除舊數據 while($redis->llen("messages") > 100) { $redis->rpop("messages"); } }); $ws->on('close', function ($ws, $fd) { $i = 0; foreach($ws->connections as $v) { if($v == $fd) { unset($ws->connections[$i]); } $i++; } }); $ws->start(); ?>

 

 

ajax.phpjquery

<?php
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $arrList = $redis->lrange("messages", 0, 20);
    $arrValue = [];
    while(count($arrList) > 0){
        $v = array_pop($arrList);
        $arrVal = json_decode($v, true);
        if($arrVal['cookieUsrName'] == $_COOKIE['userName']) {
            array_push($arrValue, '<p class="mess"><span class="mess-1">' . $arrVal['message'] . '</span><span class="mess-1-1">我</span></p>');
        }else{
            array_push($arrValue, '<p><span class="mess-2-2">' . $arrVal['username'] . '</span><span class="mess-2">' . $arrVal['message'] . '</span></p>');
        }
    }
    
    echo json_encode($arrValue);
?>

能夠經過下面的頁面查看redis數據庫裏的內容,不用去服務器端查看效果。web

showRedis.phpajax

<?php
    //鏈接本地的 Redis 服務
   $redis = new Redis();
   $redis->connect('127.0.0.1', 6379);
   
   // 獲取存儲的數據並輸出
   $arList = $redis->lrange("messages", 0 ,100);
   
   echo '當前顯示內容->' . json_decode($arList[0], true)["username"] . ":「" . json_decode($arList[0], true)["message"] . "」";
echo "<pre>"; print_r($arList); echo "</pre>";?>
相關文章
相關標籤/搜索