Swoole\WebSocket\Server->on('Handshake', fn)

Declaration

<?php
Swoole\WebSocket\Server->on('Handshake', callable $callback)

Parameters

event

The event name to set a callback for

callback

Handshake callback function, the callback function returns handshake result status.

Return

If success, it returns true, otherwise it returns false

Description

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.

Example

<?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");
    });
});