Building a Live Online Chat Room Based on Laravel + Swoole + Vue (P16)

Building a Live Online Chat Room Based on Laravel + Swoole + Vue (P16): Polling to Maintain Long Connection Optimization

In the past two days, the internal Swoole ecosystem was quarreled due to the dispute of the official framework. I suddenly remembered that the Swoole chat room project also left two small tails, one was the optimization of long-connection polling, and the other was the optimization of user authentication under WebSocket communication. The two little tails were dealt with a few years ago, and the Swoole introduction to the actual combat tutorial was ended. Arguing is their business. We focus on the technology. What should we use?

Implementation scheme

First look at the long connection polling problem. In the previous tutorial, the long connection was maintained by continuous polling. Although the process can maintain the long connection, it seems to be no different from using Ajax polling when there was no Websocket. Can you handle all communication through a Websocket connection? Obviously, Socket.io itself provides support for this, we just need to follow its communication protocol to do just fine.

Since swooletw/laravel-swoole this project Socket.io client support is very friendly, and our project Websocket used by the client is Socket.io, so we modeled in the service end swooletw/laravel-swoole of the service-side implementation to do.

Code adjustment

Added SocketIOController

First, create a SocketIOController controller to handle client establishes a connection request Websocket:

php artisan make:controller SocketIOController

Just edit the generated app/Http/Controllers/SocketIOController.php code is as follows:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SocketIOController extends Controller
{
    protected $transports = ['polling', 'websocket'];

    public function upgrade(Request $request)
    {
        if (! in_array($request->input('transport'), $this->transports)) {
            return response()->json(
                [
                    'code' => 0,
                    'message' => 'Transport unknown',
                ],
                400
            );
        }

        if ($request->has('sid')) {
            return '1:6';
        }

        $payload = json_encode([
            'sid' => base64_encode(uniqid()), 
            'upgrades' => ['websocket'],  
            'pingInterval' => config('laravels.swoole.heartbeat_idle_time') * 1000,
            'pingTimeout' => config('laravels.swoole.heartbeat_check_interval') * 1000,
        ]);

        return response('97:0' . $payload . '2:40');
    }

    public function ok()
    {
        return response('ok');
    }
}

Response data field description

The returned data here may look a bit weird, this is a format that follows the Socket.io communication protocol so that the client can identify and do the correct processing. Let’s briefly introduce the data fields returned here

'97:0' . $payload . '2:40'

Wherein 97 represents the length of data returned, 0 represented open a new connection, and then return to load data $payload:

  • sid Indicates the session ID of this communication;
  • upgrades Indicates the type of protocol to be upgraded, here it is websocket;
  • pingInterval It represents a ping long interval, the heartbeat will be appreciated that the connection is maintained for a long time;
  • pingTimeout Indicates the timeout period of this connection. A long connection does not mean that it will never be destroyed. Otherwise, system resources can never be released. After the heartbeat connection is initiated, if there is no communication beyond this timeout period, the long connection will be automatically disconnected.

Later 2 it indicates that the client sent, the server should return packet containing the same data responds (the server returns the data 3 as a prefix to indicate a response, such as sending client 2probe returned from the server 3probe, the client sends 2, returned from the server 3, which is heartbeat connection), and finally 40 in 4 represents the message data, 0 representing a message to a stream of bytes returned.

New socket.io Route

Next, in routes/web.php the new routing point to two controllers two above methods:

Route::get('/socket.io', 'SocketIOController@upgrade');
Route::post('/socket.io', 'SocketIOController@ok');

Server connection establishment code adjustment

Finally, routes/websocket.php adjust the connection is established routing codes:

WebsocketProxy::on('connect', function (WebSocket $websocket, Request $request) {
    $websocket->setSender($request->fd);
});

Delete the send welcome message code, otherwise the default response message data format will be destroyed, causing the Socket.io client to fail to parse normally, and constantly initiate client connection establishment requests.

Client connection establishment code adjustment

Because here the inlet Websocket establish routing connections to adjust /socket.io, so it needs to adjust the front end of resources/js/socket.js the code:

import io from 'socket.io-client';
const socket = io('http://webchats.test');
export default socket;

Since Socket.io default path connection is established socket.io, it may be omitted corresponding to paththe configuration, transport the configuration may also be removed, because they can now return data transfer in accordance with the server protocol used is determined automatically.

Recompile the front-end resources:

npm run dev

Nginx configuration adjustment

The best, we must adjust the Nginx virtual host configuration, will be /ws adjusted to /socket.io:

location ^~ /socket.io {
    ...
}

Testing new Websocket communication

Refactor the Nginx container and restart all services:

docker-compose build nginx
docker-compose down
docker-compose up -d nginx mysql redis

Then enter the workspace container starts Websocket server:

cd webchat
bin/laravels start

Visit the chat room page again to log in, enter the room, chat, exit the room, etc. You can see in the developer console that all Websocket message flows are completed in one connection:

This is image title

This completes the code length remains connected by polling optimization, based Socket.io client to send the heartbeat connection is maintained long way connector (sending client 2, the server returns 3 the response as), of course, if the heartbeat connection is initiated If there is no communication after the timeout period, the long connection will be disconnected:

This is image title

There is another one here 5, which means that before switching the transmission protocol (such as upgrading to Websocket), it will test whether the server and client can communicate through this transmission. If the test is successful, the client will send an upgrade data packet and request the server to refresh the old transmission Cache and switch to the new transfer.

#laravel #swoole #vue

Building a Live Online Chat Room Based on Laravel + Swoole + Vue (P16)
7.70 GEEK