Developing WebSocket online chat communication system with PHP

Need Swoole with thinkp5

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.)

namespace app\home\controller;
use think\swoole\Server;
class WebSocket extends Server
    protected $host = ''; //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));
        //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">
<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" />
<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>
    <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>
    <!-- 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>
    <!-- bottom end-->
<script src=""></script>
<script src=""></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://"+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(;
            //Error prompt
            if(data.status != 1){
            //Message return
            if (data.status==1 &&!='') {
                var html = "";
                if ( == uid) {
                    html += "<div style='word-break:break-all' class=\"show\"><div class=\"time\">""</div><div class=\"msg\"><img src=\"""\" alt=\"\" /><p><i clas=\"msg_input\"></i>""</p></div></div>";
                    html += "<div style='word-break:break-all' class=\"send\"><div class=\"time\">""</div><div class=\"msg\"><img src=\"""\" alt=\"\" /><p><i clas=\"msg_input\"></i>""</p></div></div>";
            setTimeout(function () {
                ($('.message').children("div:last-child")[0]).scrollIntoView();//scroll up
        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;
        //Carriage return
        $("#msg").keydown(function (evel) {
            var that = $(this);
            if (evel.keyCode == 13) {
                evel.cancelBubble = true;
                var contents = that.val().trim();
                if(contents == null || contents == ""){
                    layer.msg('Content is empty',{shade:0.1,icon:2,time:600});              
                    return false;
        layer.alert("Your browser does not support WebSocket!");

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

phper always encounters some problems and bottlenecks in its advanced stage. There is no sense of direction when it writes more business code. I don't know where to start to improve. For this, I collated some data, including but not limited to: distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, laravel, YII2, Redis, Swoole, Swoft, Kafka, Mysql optimization, shell Script, Docker, microservice, Nginx and other advanced dry goods can be shared for free Please poke here.

Tags: PHP JQuery Javascript socket

Posted on Mon, 11 Nov 2019 11:51:14 -0500 by angrytuna