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?
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.
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');
}
}
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.
socket.io
RouteNext, 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');
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.
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
The best, we must adjust the Nginx virtual host configuration, will be /ws
adjusted to /socket.io
:
location ^~ /socket.io {
...
}
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 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:
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