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

Latest version: pecl install openswoole-22.1.2 | composer require openswoole/core:22.1.5

Declaration

<?php OpenSwoole\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 OpenSwoole\WebSocket\Server;
use OpenSwoole\Http\Request;
use OpenSwoole\WebSocket\Frame;

$server = new Server("127.0.0.1", 9501);

$server->on("Start", function(Server $server)
{
    echo "OpenSwoole WebSocket Server started at http://127.0.0.1:9501\n";
});

$server->on('handshake', function (OpenSwoole\HTTP\Request $request, OpenSwoole\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, OpenSwoole\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 OpenSwoole 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 (\OpenSwoole\Http\Request $request, \OpenSwoole\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");
    });
});
Last updated on September 1, 2022