Home About Me

Using Swoole WebSocket to Count How Many Pages Are Open Right Now

The effect I was after is the same as the page counter at the bottom of this site — the one built on Workerman and socket.io.

page counter showing how many pages are currently open

I'd been meaning to rebuild that counter with Swoole's WebSocket support for a while, and I finally sat down and read through the Swoole docs. Earlier I'd looked at a couple of the laravel-swoole packages people have put together, but since I never got to use them at work, the whole thing slipped my mind.

What it really comes down to is getting the three WebSocket events straight: open, message, and close. For the browser side I followed the HTML5 WebSocket reference; for the server side, the Swoole WebSocket documentation.

Client side

<span id="see">一共打开 <b id="count">1</b> 个页面</span>
</body>
<script type="text/javascript">
    // open a web socket
    let ws = new WebSocket("ws://127.0.0.1:9501");
    ws.onopen = function (evt) {
        // the Web Socket is connected, use send() to push data
        ws.send("发送数据");
        console.log("Web Socket 已连接上,使用 send() 方法发送数据");
    };

    ws.onmessage = function (evt) {
        let received_msg = evt.data;
        document.getElementById('count').innerHTML = received_msg;
        console.log("数据已接收..." + received_msg);
    };
</script>

The page opens one socket to the server and sends a first message as soon as the connection is live. From then on it just sits and listens: every time the server pushes a new number, the count element is overwritten with it. Nothing else on the page has to know about the connection.

Server side

public function run()
{
    $this->server->on('open', [$this, 'open']);

    $this->server->on('message', [$this, 'message']);

    $this->server->on('close', [$this, 'close']);

    $this->server->start();
}

Three callbacks do all the work. open fires when a browser connects — that's where the current count goes up and where the new total gets pushed out to everyone. message handles whatever the client sends (here, just the initial ping after connecting). close fires when the tab goes away or the connection drops, and the count goes back down. Every time the number changes, the same value is broadcast to all connected clients, so the counter stays in sync across tabs and browsers.

A working demo is available on Gitee if you want to see the handlers filled in.

-- END