WebSocketプロトコル

現在のWorkermanのWebSocketプロトコルバージョンは13です。

WebSocketプロトコルはHTML5の新しいプロトコルです。これにより、ブラウザとサーバー間での全二重通信が実現されます。

WebSocketとTCPの関係

WebSocketはHTTPと同様にアプリケーション層のプロトコルであり、どちらもTCPに基づいて伝送されます。WebSocket自体はSocketとはあまり関係がなく、同じものとして考えるべきではありません。

WebSocketプロトコルのハンドシェイク

WebSocketプロトコルにはハンドシェイクのプロセスがあり、ハンドシェイク時にはブラウザとサーバーがHTTPプロトコルを使用して通信します。Workermanでは、以下の方法でハンドシェイクプロセスに介入することができます。

Workermanが <= 4.1 の場合

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Connection\TcpConnection;
use Workerman\Worker;

$ws = new Worker('websocket://0.0.0.0:8181');
$ws->onConnect = function($connection)
{
    $connection->onWebSocketConnect = function($connection , $httpBuffer)
    {
        // ここで接続元が合法かどうかを判断できます。 不合法の場合は接続を閉じます。
        // $_SERVER['HTTP_ORIGIN']はどのサイトからWebSocket接続が発起されたかを示します。
        if($_SERVER['HTTP_ORIGIN'] != 'https://www.workerman.net')
        {
            $connection->close();
        }
        // onWebSocketConnect内では$_GETと$_SERVERが使用できます。
        // var_dump($_GET, $_SERVER);
    };
};
Worker::runAll();

Workermanが >= 5.0 の場合

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Worker;

$worker = new Worker('websocket://0.0.0.0:12345');
$worker->onWebSocketConnect = function (TcpConnection $connection, Request $request) {
    if ($request->header('origin') != 'https://www.workerman.net') {
        $connection->close();
    }
    var_dump($request->get());
    var_dump($request->header());
};
Worker::runAll();

WebSocketプロトコルによるバイナリデータの送信

WebSocketプロトコルはデフォルトでutf8テキストのみを送信できます。バイナリデータを送信する場合は、以下の部分を読んでください。

WebSocketプロトコルでは、プロトコルヘッダ内にバイナリデータかutf8テキストデータかを示すフラグが使用されます。ブラウザは、フラグと送信されるコンテンツのタイプが一致するかを検証し、一致しない場合はエラーが発生し接続が切断されます。

そのため、サーバーがデータを送信する際には、送信するデータのタイプに応じてこのフラグを設定する必要があります。Workermanでは、通常のutf8テキストの場合、次のように設定します(デフォルトでこの値なので、手動で設定する必要はありません)。

use Workerman\Protocols\Websocket;
$connection->websocketType = Websocket::BINARY_TYPE_BLOB;

もしバイナリデータの場合は、次のように設定します。

use Workerman\Protocols\Websocket;
$connection->websocketType = Websocket::BINARY_TYPE_ARRAYBUFFER;

注意:もし$connection->websocketTypeが設定されていない場合、$connection->websocketTypeはデフォルトでBINARY_TYPE_BLOB(すなわちutf8テキストタイプ)となります。一般的なアプリケーションが送信するのはutf8テキストであり、例えばjsonデータを送信する場合が多いため、通常は$connection->websocketTypeを手動で設定する必要はありません。バイナリデータを送信する場合(例えば画像データやprotobufferデータなど)のみ、プロパティをBINARY_TYPE_ARRAYBUFFERに設定する必要があります。

WorkermanをWebSocketクライアントとして利用する

AsyncTcpConnectionクラスを利用してwsプロトコルを使うことで、WorkermanをWebSocketクライアントとしてリモートWebSocketサーバーに接続し、双方向リアルタイム通信を実現できます。