1. 程式人生 > 其它 >socket 傳送陣列_讓 WebSocket 更友好:給 Hyperf 加上 socket.io 支援

socket 傳送陣列_讓 WebSocket 更友好:給 Hyperf 加上 socket.io 支援

技術標籤:socket 傳送陣列

有小夥伴抱怨道,WebSocket Server感覺太原始,沒有“框架感”。

Http 是一個表達能力非常豐富的協議。除了Header,Body等基本定義外,通過一系列RFC,它還帶來了一些廣泛接受的規範,比如querystring是怎麼劃分的,formdata是什麼樣的,multipart又是什麼樣的。基於這些規範,框架可以靈活的設計路由器、控制器、請求物件、響應物件等等。

我們今天討論的主角,WebSocket協議,雖然也是建立在Http之上,但是卻沒有定義Frame的內容應該是什麼樣的。

Frame裡可以是JSON:

{"event": "orderCreated", "data":{"orderId": 123}}

也可以是字串

orderCreated|orderId:123

還可以是二進位制

0101010101010101

所以作為框架來講,處理WebSocket是沒有抓手的。有點類似於封裝TCP Server,只能做到管理連線建立和關閉這樣的顆粒度,Frame裡的資訊只能黑箱處理。於是小夥伴在用WebSocket Server時,便會覺得沒有Http Server封裝度高。

當我們對Frame約定一個結構時,框架就大有可為了。

http://Socket.io就是一套非常流行的WebSocket應用層協議。(http://Socket.io不止於WebSocket,不過在2020年的今天,不支援WebSocket的瀏覽器基本絕跡,其他XHR Polling等方式也就邊緣化了)。

我們先過於簡略地來看一下http://Socket.io協議。

0 是連線建立。

1 是連線關閉。

2 是天王蓋地虎 (ping)

3 是寶塔鎮河妖 (pong)

4 是傳遞資訊。

傳遞資訊時又要細分。

42 是一條新資訊。

43 是一條回覆資訊。

42123 是一條id為123的資訊。

43123 是對剛才123號資訊的回覆。

傳送資訊時,內容是一個JSON陣列,陣列第一個引數固定是事件名。 比如

42123["orderCreated", {"orderId": 123}]

約定了如上的基本結構,框架就有發揮空間了。

在Hyperf1.1.30版本中,你可以這樣建立一個http://Socket.io服務。

<?php
/**
 * @SocketIONamespace("/")
 */
class WebSocketController extends BaseNamespace
{
    /**
     * @Event("event")
     * @param string $data
     */
    public function onEvent(Socket $socket, $data)
    {
        // 應答
        return 'Event Received: ' . $data;
    }

    /**
     * @Event("join-room")
     * @param string $data
     */
    public function onJoinRoom(Socket $socket, $data)
    {
        // 將當前使用者加入房間
        $socket->join($data);
        // 向房間內其他使用者推送(不含當前使用者)
        $socket->to($data)->emit('event', $socket->getSid() . "has joined {$data}");
        // 向房間內所有人廣播(含當前使用者)
        $this->emit('event', 'There are ' . count($socket->getAdapter()->clients($data)) . " players in {$data}");
    }

    /**
     * @Event("say")
     * @param string $data
     */
    public function onSay(Socket $socket, $data)
    {
        $data = Json::decode($data);
        $socket->to($data['room'])->emit('event', $socket->getSid() . " say: {$data['message']}");
    }
}

我們可以看到,支援的功能豐富多了,可以通過@Event()註解進行事件的分發,在控制器裡通過return來對事件進行ACK,實現房間分組、廣播、私聊等等。

還有一點這裡沒有體現。藉助Redis PubSub,hyperf/socketio-server元件還封裝了跨機器的實時通訊,開箱就是分散式。

詳細的功能清單,可以查閱1.1.30版本的Hyperf文件,這裡就不再贅述了。

希望http://Socket.io協議的支援,可以讓WebSocket更好用,不再有開篇提到的困惑。