ThinkPHP uses Swoole to realize WebSocket online chat communication system

Keywords: PHP JQuery Javascript socket

To use Swoole in ThinkPHP, you need to install the think Swoole composer package, provided that the system has installed the Swoole PECL extension.

To install think swoole, execute the composer command in the project root directory of tp5:

composer require topthink/think-swoole

If you don't say much, go straight to the code:

To create a WebSocket.php controller:

(to confirm that the server is allowed to listen to the port, you need to add security group rules in pagoda environment.)

<?php
 
namespace app\home\controller;
use think\swoole\Server;
class WebSocket extends Server
{
    protected $host = '0.0.0.0'; //Listen to all addresses
    protected $port = 9501; //Listen to port 9501
    protected $serverType = 'socket';
    protected $option = [ 
        'worker_num'=> 4, //Set the number of Worker processes started
        'daemonize'    => false, //Daemonization (change online to true)
        'backlog'    => 128, //Listen queue length
        'dispatch_mode' => 2, //Fixed mode to ensure that the data sent from the same connection will only be processed by the same worker
 
        //Heartbeat detection: traverse all connections every 60 seconds, and forcibly close the connection without sending any data to the server within 10 minutes.
        'heartbeat_check_interval' => 60,
        'heartbeat_idle_time' => 600
    ];
 
    //Callback function when establishing connection
    public function onOpen($server,$req)
    {
        $fd = $req->fd;//Client identity
        $uid = $req->get['uid'];//User id passed by the client
        $token = $req->get['token'];//User login token passed by client
        
        //Omit token validation logic...
        if (!$token) {
            $arr = array('status'=>2,'message'=>'token Expired');
            $server->push($fd, json_encode($arr));
            $server->close($fd);
            return;
        }
        //Omit binding fd logic to user...
        echo "user{$uid}Connection established,Identified as{$fd}\n";
    }
 
    //Callback function when receiving data
    public function onMessage($server,$frame)
    {
        $fd = $frame->fd;
        $message = $frame->data;
 
        //Omit querying user uid logic through fd...
        $uid = 666;
        $data['uid'] = $uid;
        $data['message'] = 'user'.$uid.'Sent:'.$message;
        $data['post_time'] = date("m/d H:i",time());
        $arr = array('status'=>1,'message'=>'success','data'=>$data);
 
        //Push to current connected users only
        //$server->push($fd, json_encode($arr));
        
        //Push to all connected users
        foreach($server->connections as $fd) {
            $server->push($fd, json_encode($arr));
        } 
    }
 
    //Callback function when connection is closed
    public function onClose($server,$fd)
    {
        echo "Identification{$fd}Connection closed\n";
    }
}

Front end demo page:

(omit the logic of the controller to judge the login status and allocate data...)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>Chat</title>
<link rel="stylesheet" type="text/css" href="/static/liaotian/chat.css" />
<script src="/static/liaotian/js/jquery.min.js"></script>
<script src="/static/liaotian/js/flexible.js"></script>
</head>
<body>
    <header class="header">
        <a class="back" href="javascript:history.back()"></a>
        <h5 class="tit">chat online</h5>
        <a href=""><div class="right">Sign out</div></a>
    </header>
 
    <!-- Chat content start-->
    <div class="message"> </div>
    <!-- Chat content end-->
 
    <!-- bottom start-->
    <div class="footer">
        <img id="setbtn" src="/static/liaotian/images/hua.png" alt="" />
        <img src="/static/liaotian/images/xiaolian.png" alt="" />
        <input type="text" id="msg" value="" maxlength="300">
        <p style="background: rgb(17, 79, 142);" id="sendBtn">Send out</p>
    </div>
    <!-- bottom end-->
</body>
</html>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/layer/3.1.0/layer.js"></script>
<script type="text/javascript">
$(function () {
    var uid = 666;//Current user id
    var token = 'abcdefg';//User token
 
    //Determine whether the browser supports WebSocket
    var supportsWebSockets = 'WebSocket' in window || 'MozWebSocket' in window;
    if (supportsWebSockets) {
        //Establish WebSocket connection (change ip address to host ip)
        var ws = new WebSocket("ws://127.0.0.1:9501?uid="+uid+"&token="+token);
        ws.onopen = function () {
            layer.msg('Server connection successful',{shade:0.1,icon:1,time:600});
        };
        ws.onerror = function () {
            layer.msg('Server connection failed',{shade:0.1,icon:2,time:600});
        };
        ws.onmessage = function (evt) {
            var data = $.parseJSON(evt.data);
            //Error prompt
            if(data.status != 1){
                layer.alert(data.message,{icon:2});
                return;
            }
            //Message return
            if (data.status==1 && data.data.message!='') {
                var html = "";
                if (data.data.uid == uid) {
                    html += "<div style='word-break:break-all' class=\"show\"><div class=\"time\">"+data.data.post_time+"</div><div class=\"msg\"><img src=\""+data.data.head_img+"\" alt=\"\" /><p><i clas=\"msg_input\"></i>"+data.data.message+"</p></div></div>";
                }else{
                    html += "<div style='word-break:break-all' class=\"send\"><div class=\"time\">"+data.data.post_time+"</div><div class=\"msg\"><img src=\""+data.data.head_img+"\" alt=\"\" /><p><i clas=\"msg_input\"></i>"+data.data.message+"</p></div></div>";
                }
            }
            $(".message").append(html);
            setTimeout(function () {
                ($('.message').children("div:last-child")[0]).scrollIntoView();//scroll up
            },100);
        };
        ws.onclose = function (res) {
            
        };
        //Push button to send
        $("#sendBtn").click(function () {
            var contents = $("#msg").val().trim();
            if(contents == null || contents == ""){
                layer.msg('Content is empty',{shade:0.1,icon:2,time:600});            
                return false;
            }else{
                ws.send(contents);
                $("#msg").val("");
            }
        });
        //Carriage return
        $("#msg").keydown(function (evel) {
            var that = $(this);
            if (evel.keyCode == 13) {
                evel.cancelBubble = true;
                evel.preventDefault();
                evel.stopPropagation();
                var contents = that.val().trim();
                if(contents == null || contents == ""){
                    layer.msg('Content is empty',{shade:0.1,icon:2,time:600});              
                    return false;
                }else{
                    ws.send(contents);
                    that.val("");
                }
            }
        });
    }else{
        layer.alert("Your browser does not support WebSocket!");
    }
});
</script>

Move the server to the project root directory to start the service:

php public/index.php Websocket/start

The path here is because I bound the home module as the default module. The default situation of tp5 is: php public/index.php index/Websocket/start)

Open successfully. Check whether the port has been monitored:

lsof -i:9501

The demonstration effect is as follows:

I believe that many friends want to learn more about swoole, laravel and thinkphp. swoft microservices encounter many difficulties in use. In order to advance PHP architects as soon as possible, you can refer to this PHP architect roadmap and architecture tutorial. Please poke here.

Posted by chwebdesigns on Fri, 18 Oct 2019 09:09:25 -0700