WebSocket 協議

目前 Workerman 的 WebSocket 協議版本為 13

WebSocket protocol 是 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 伺服器,完成雙向即時通訊。