Join 4,000+ others and never miss out on new tips, tutorials, and more.
4.x is outdated, please check the latest version 22.x
Latest version:
pecl install openswoole-22.1.2
<?php Swoole\WebSocket\Server->on('Handshake', callable $callback)
The event name to set a callback for
Handshake callback function, the callback function returns handshake
result status.
If success, it returns true
, otherwise it returns false
This function is optional to create a WebSocket server.
This function is executed when a WebSocket connection is established and going into the handshake
stage.
The built-in default handshake
protocol is Sec-WebSocket-Version: 13
. You can override the default handshake
protocol by implementing this function, otherwise you can leave out this event.
If you set your own handshake function, the server will not call the Open
event, your application needs to handle this. You can use $server->defer()
to replicate Open
event logic (see example).
When implementing a custom handshake you must call $response->status(101)
and $response->end()
in order to complete the handshake otherwise it will fail.
<?php
use Swoole\WebSocket\Server;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
$server = new Server("127.0.0.1", 9501);
$server->on("Start", function(Server $server)
{
echo "Swoole WebSocket Server started at http://127.0.0.1:9501\n";
});
$server->on('handshake', function (Swoole\HTTP\Request $request, Swoole\HTTP\Response $response)
{
$secWebSocketKey = $request->header['sec-websocket-key'];
$patten = '#^[+/0-9A-Za-z]{21}[AQgw]==$#';
// At this stage if the socket request does not meet custom requirements, you can ->end() it here and return false...
// Websocket handshake connection algorithm verification
if (0 === preg_match($patten, $secWebSocketKey) || 16 !== strlen(base64_decode($secWebSocketKey)))
{
$response->end();
return false;
}
echo $request->header['sec-websocket-key'];
$key = base64_encode(sha1($request->header['sec-websocket-key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
$headers = [
'Upgrade' => 'websocket',
'Connection' => 'Upgrade',
'Sec-WebSocket-Accept' => $key,
'Sec-WebSocket-Version' => '13',
];
// WebSocket connection to 'ws://127.0.0.1:9501/'
// Failed: Error during WebSocket handshake:
// Response must not include 'Sec-WebSocket-Protocol' header if not present in request: websocket
if(isset($request->header['sec-websocket-protocol']))
{
$headers['Sec-WebSocket-Protocol'] = $request->header['sec-websocket-protocol'];
}
foreach($headers as $key => $val)
{
$response->header($key, $val);
}
$response->status(101);
$response->end();
echo "connected!" . PHP_EOL;
return true;
});
$server->on('Open', function(Server $server, Swoole\Http\Request $request)
{
echo "connection open: {$request->fd}\n";
$server->tick(1000, function() use ($server, $request)
{
$server->push($request->fd, json_encode(["hello", time()]));
});
});
$server->on('Message', function(Server $server, Frame $frame)
{
echo "received message: {$frame->data}\n";
$server->push($frame->fd, json_encode(["hello", time()]));
});
$server->on('Close', function(Server $server, int $fd)
{
echo "connection close: {$fd}\n";
});
$server->start();
By implementing your own HandShake algorithm handles the connection establishment and validation, the Swoole server won't trigger the Open
event. Instead you need to implement this logic, this can be easily done with $server->defer()
.
<?php
$server->on('Handshake', function (\Swoole\Http\Request $request, \Swoole\Http\Response $response) use ($server) {
// Handshake verification completed, validate request...
$response->status(101);
$response->end();
$fd = $request->fd;
// Same logic as the server Open event, will not block
$server->defer(function() use ($fd, $server)
{
echo "Client connected\n";
$server->push($fd, "hello, welcome\n");
});
});