The instant messaging function of chat room is realized by websocket based on swoole

Time:2021-8-23

The instant messaging function of chat room is realized by websocket based on swoole

preface

Some time ago, if you haven’t just built a local development environment, you have to do something. After reading the development documents of swoole, let’s try websocket to get instant messaging first. Then arrange a chat room and start

What is swoole

Swoole is a high-performance network communication engine of PHP. It is written in C / C + + language and provides network server and client modules of various communication protocols. It can easily and quickly realize TCP / UDP services, high-performance web, websocket services, Internet of things, real-time communication, games, micro services, etc., so that PHP is no longer limited to the traditional web field.

As can be seen from the official introduction,SwoolesupportWebsocket service, we use this to quickly develop a simple chat room.

Chat room effect

First, enter the project root directory and execute the commandphp SwooleChat.phpopenWebSocketService, and then double-clickchat.htmlOpen the file in the browser, enter the chat interface, and you can start blowing water happily

The instant messaging function of chat room is realized by websocket based on swoole

Server side (swoolechat. PHP)

From the official document websocket server, you can see that the PHP server side mainly includesonOpenonMessageandonClose, the functions of these three events are as follows:

  • Onopen: listen for websocket connection opening events
  • Onmessage: listen for websocket message events
  • Onclose: listens for websocket connection closing events

Create MySQL data table

Here, we mainly create a new table. Here, we create a new database namedchat, and then create a new chat user tablechat_user, the SQL statement for creating tables is as follows

CREATE TABLE `chat_user` (
  `id` int(11) NOT NULL AUTO_ Increment comment 'primary key',
  `FD ` int (10) unsigned not null default '0' comment 'push ID',
  `user_ name` varchar(50) CHARACTER SET utf8 COLLATE utf8_ general_ Ci not null default '' comment 'user name',
  `avatar` varchar(100) CHARACTER SET utf8 COLLATE utf8_ general_ Ci not null default '' comment 'Avatar',
  `online_ Status ` tinyint (3) unsigned not null default '1' comment 'online status: 0 offline, 1 online',
  `add_ Time ` int (10) unsigned not null default '0' comment 'registration time',
  `update_ Time ` int (10) unsigned not null default '0' comment 'update time',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

Onopen listens to websocket connection open

When a new user opens a websocket connection, he will goonOpenEvent, I simply encapsulate it according to the official example. After the user creates a connection, the user information is stored in theMySQLDatabase and notify other online users. By the way, remind me, it’s used hereMySQL, if not installed, please install the relevant extensions first.

/**
 *Listening to websocket connection open
 */
private function open()
{
    $this->ws->on('open', function ($ws, $request) {
        //User stored in database
        $this->initConn();
        $user_name = $request->get['user_name'];
        $fd = $request->fd;
        $sql = "INSERT INTO chat_user (fd, user_name, add_time) VALUES ($fd, '{$user_name}', " . time() . ")";
        $this->conn->query($sql);
        //Push online notification
        $this->return['type'] = 'on';
        $this - > return ['msg '] =' welcome ['. $user_ Name. '] enter the chat room';
        //User list
        $sql = "SELECT fd,user_name FROM chat_user WHERE online_status = 1";
        $result = $this->conn->query($sql);
        $user_list = [];
        if (mysqli_num_rows($result) > 0) {
            //Push online notification to other users
            while ($row = mysqli_fetch_assoc($result)) {
                $user_list[] = ['fd' => $row['fd'], 'name' => $row['user_name']];
                if ($row['fd'] != $fd) {
                    $this->return['data'] = ['fd' => $fd, 'name' => $user_name];
                    $ws->push($row['fd'], json_encode($this->return));
                }
            }
        }
        //Online users
        $this->return['type'] = 'open';
        $this->return['data'] = ['user_list' => $user_list];
        $ws->push($fd, json_encode($this->return));
    });
}

Onmessage listens for websocket messages

The message sent by the client needs to be pushed to other people in the chat room, and tell other users who sent this message and when.

/**
 *Listening for websocket messages
 */
private function message()
{
    $this->ws->on('message', function ($ws, $frame) {
        $this->initConn();
        //Chat message
        $fd = $frame->fd;
        $message = $frame->data;
        $this->return['type'] = 'chat';
        $this->return['msg'] = $message;
        //User name
        $sql = "SELECT user_name FROM chat_user WHERE fd = {$fd} LIMIT 1";
        $res = $this->conn->query($sql);
        $user = $res->fetch_assoc();
        $user_name = $user['user_name'];
        //User list
        $sql = "SELECT fd,user_name FROM chat_user WHERE online_status = 1 ORDER BY id desc";
        $result = $this->conn->query($sql);
        if (mysqli_num_rows($result) > 0) {
            //Push sent messages
            while ($row = mysqli_fetch_assoc($result)) {
                $this->return['data'] = ['user_name' => $user_name, 'from' => $fd, 'to' => $row['fd'], 'time' => date('Y-m-d H:i:s')];
                $ws->push($row['fd'], json_encode($this->return));
            }
        }
    });
}

Onclose listens for websocket connection closure

When the client connection is closed, it is necessary to handle that the user status is offline and inform other online users that the user has left the chat room offline.

/**
 *Listening for websocket connection closure
 */
private function close()
{
    $this->ws->on('close', function ($ws, $fd) {
        $this->initConn();
        //User offline
        $sql = "UPDATE chat_user SET online_status = 0 WHERE fd = $fd";
        $this->conn->query($sql);
        //User name
        $sql = "SELECT user_name FROM chat_user WHERE fd = {$fd} LIMIT 1";
        $res = $this->conn->query($sql);
        $user = $res->fetch_assoc();
        $user_name = $user['user_name'];
        //User list
        $sql = "SELECT fd,user_name FROM chat_user WHERE online_status = 1 ORDER BY id desc";
        $result = $this->conn->query($sql);
        if (mysqli_num_rows($result) > 0) {
            //Push offline notification to other users
            while ($row = mysqli_fetch_assoc($result)) {
                if ($row['fd'] != $fd) {
                    $this->return['type'] = 'off';
                    $this->return['msg'] = '【' . $user_ Name. '] leave the chat room';
                    $this->return['data'] = ['fd' => $fd];
                    $ws->push($row['fd'], json_encode($this->return));
                }
            }
        }
    });
}

Client (chat. HTML)

HTML interface

Interface, in order to be simple and fast, I used bootstrap, which can quickly write a simple chat room page

<head>
    <meta charset="UTF-8">
    < title > chat room < / Title >
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="page-header">
            <h2>Websocket chat room based on swoole</h2>
        </div>
        <div class="col-xs-9 col-sm-9 col-md-9">
            <div class="form-group send-message">
                <textarea name="message" rows="5" class="form-control col-xs-12 col-sm-12 col-md-12"
                          Placeholder = "please enter chat content" > < / textarea >
                < button type = "button" class = "BTN info BTN block send button" > send < / button >
            </div>
        </div>
        <div class="col-xs-3 col-sm-3 col-md-3">
            <h3>Online users</h3>
            <table class="table table-hover online-user">
                <tr>
                    < th > FD No. < / th >
                    < th > user name < / th >
                </tr>
            </table>
        </div>
    </div>
</div>
</body>
<script integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous">
</script>
<script></script>

JS interaction

Similarly, we can see from the example that the main events on the client side are the same as those on the server side, that is, the establishment of the client sidewsAfter connection, you need to process the messages corresponding to various events pushed from the server, mainly processing uplink and offline message notifications and ordinary chat messages; In order to save trouble, I have directly obtained the user name here at random. Don’t say I’m lazy.

<script>
    //Random user name
    var user_name = 'user-' + Math.floor(Math.random() * 10000 + 1);
    //Establish WS connection
    var wsServer = 'ws://127.0.0.1:9502?user_name=' + user_name;
    var websocket = new WebSocket(wsServer);
    websocket.onmessage = function (evt) {
        var data = jQuery.parseJSON(evt.data);
        console.log(data);
        if (data.type == 'open') {
            //Just connected, initialize user data
            var user_list = data.data.user_list;
            var open_html = '';
            $.each(user_list, function (k, val) {
                open_html += '<tr data-id="' + val.fd + '"><td>' + val.fd + '</td> <td>' + val.name + '</td> </tr>';
            });
            $('.online-user').append(open_html);
        } else if (data.type == 'chat') {
            //Chat message push
            var is_myself = '';
            if (data.data.from == data.data.to) {
                is_myself = ' text-right';
            }
            var chat_html = '<div class="panel panel-info">' +
                    '<div class="panel-heading ' + is_myself + '">【' + data.data.user_name + '】 ' + data.data.time + '</div>' +
                    '<div class="panel-body ' + is_myself + '">' + data.msg +
                    '</div></div>';
            $('.send-message').before(chat_html);
        } else if (data.type == 'on') {
            //New user connection
            var on_html = '<tr data-id="' + data.data.fd + '"><td>' + data.data.fd + '</td> <td>' + data.data.name + '</td> </tr>';
            $('.online-user').append(on_html);
            //Online welcome
            var notice_html = '<div class="panel panel-info">' +
                    '<div class="panel-body text-center">' + data.msg +
                    '</div></div>';
            $('.send-message').before(notice_html);
        } else if (data.type == 'off') {
            //User closes connection
            $('.online-user').find('tr[data-id=' + data.data.fd + ']').remove();
            //Offline reminder
            var off_html = '<div class="panel panel-info">' +
                    '<div class="panel-body text-center">' + data.msg +
                    '</div></div>';
            $('.send-message').before(off_html);
        }
    };
    websocket.onopen = function (evt) {
        console.log("Connected to WebSocket server.");
    };
    websocket.onclose = function (evt) {
        Alert ('the server has been disconnected and will start reconnection ');
        window.location.reload();
    };
    websocket.onerror = function (evt, e) {
        console.log('Error occured: ' + evt.data);
    };
    $(".send-button").off('click').on('click', function () {
        var message = $("textarea[name=message]").val().trim();
        if (message == '') {
            Alert ('Please input chat content... ');
            return false;
        }
        websocket.send(message);
        $("textarea[name=message]").val('');
    });
</script>

Complete source code

For convenience, I will certainly share the complete source code. Although it says a pile of core code, it is still hard to run together. As a conscientious brick Porter, I will certainly give you the code that can run directly as long as the environment is OK. You may want to say:BB is easy, Show me the code.Well, I have uploaded the source code to GitHub dating website. You can check it.

  • Complete source code of chat room: https://github.com/gxcuizy/Blog/blob/master/chat
  • Server side source code: swoolechat.php
  • Client source code: chat.html

summary

This is just a simple chat room. It is only for learning reference and communication. If you have any questions or don’t understand, you can leave a message to communicate with me and learn and make progress together. Thank you.