Think-Swoole之WebSocket消息、廣播以及 Swoole 原生方法調用

think-swoole 教程之websocket 消息、廣播以及 swoole 原生方法調用

什么是客戶端的 fd

fd 是在 Swoole 中客戶端的唯一標識符,fd 是復用的,當連接關閉后 fd 會被新進入的連接復用,正在維持的 TCP 連接 fd 不會被復用。

獲取當前客戶端的fd

app/listener/WsConnect.php

<?php declare (strict_types = 1); namespace applistener; use thinkswooleWebsocket; class WsTest {     /**      * 事件監聽處理      *      * @return mixed      */     public function handle($Event,Websocket $ws) { //        $ws = app(&#39;thinkswooleWebsocket&#39;); // 單例         //獲取當前發送消息客戶端的 fd         var_dump($ws ->?getSender()); ????} }

test.html

nbsp;HTML&gt;   ????<meta> ????<title>Document</title> 消息:<input> 接收者:<input><button>發送</button> <script>     var ws = new WebSocket("ws://127.0.0.1:9501/");     ws.onopen = function(){         console.log(&#39;連接成功&#39;);     }     ws.onmessage = function(data){         console.log(data.data);     }     ws.onclose = function(){         console.log(&#39;連接斷開&#39;);     }     function send() {         var message = document.getElementById(&#39;message&#39;).value;         var to = document.getElementById(&#39;to&#39;).value;         console.log("準備給" + to + "發送數據:" + message);         ws.send(JSON.stringify([&#39;test&#39;,{             to:to,             message:message         }])); //發送的數據必須是 [&#39;test&#39;,數據] 這種格式     } </script>

瀏覽器打開多個標簽,來模擬多個客戶端連接,均訪問 test.html 文件,控制臺將會打印出每個客戶端的 fd ,如下圖我們打開三個標簽進行訪問:

Think-Swoole之WebSocket消息、廣播以及 Swoole 原生方法調用

也就是說,服務端發送過來的消息,都會被 HTML 中的 ws.onmessage 接收到。

給指定 fd 的客戶端發送消息(單發、群發)

app/listener/WsTest.php

<?php declare (strict_types = 1); namespace applistener; use thinkswooleWebsocket; class WsTest {     /**      * 事件監聽處理      *      * @return mixed      */     public function handle($event,Websocket $ws) { //        $ws = app(&#39;thinkswooleWebsocket&#39;); // 單例         //獲取當前發送消息客戶端的 fd         var_dump($ws ->?getSender()); ????????//發送給指定?fd?的客戶端,包括發送者自己 ????????$ws?-&gt;?to(intval($event['to']))?-&gt;?emit('testcallback',$event['message']); ????} }

$ws -> to()是設置收件人 fd 或聊天室名,如果發送給多個人可以數組設置多個,例如 [1,2,3],fd 須為整型。$ws -> emit() 是發送消息方法,第一個參數是事件名稱,用于多場景,可任意定義,就如上一片文章中客戶端給服務端發送消息的 Test 一樣。第二個參數是發送的內容,可以是字符串、數組,單獨調用不設置收件人的話,就是發送消息給當前 fd 。

重啟 Think-Swoole 服務,分別打開三個客戶端進行連接,fd 分別為 1、2、3,現在,現在,我們用 fd 為 1 的客戶端,發消息給 fd 為 2 的客戶端:

Think-Swoole之WebSocket消息、廣播以及 Swoole 原生方法調用

發送后,可見只有 fd 為 1、2 的客戶端能收到消息(也就是說消息發出者自身也會收到消息),而 fd 為 3 的客戶端卻沒有收到消息:

Think-Swoole之WebSocket消息、廣播以及 Swoole 原生方法調用

發送后,可見只有 fd 為 1、2 的客戶端能收到消息(也就是說消息發出者自身也會收到消息),而 fd 為 3 的客戶端卻沒有收到消息:

Think-Swoole之WebSocket消息、廣播以及 Swoole 原生方法調用

發送廣播消息

廣播消息就是發送一條消息給所有客戶端,但是不包括自己。

app/listener/WsConnect.php

<?php declare (strict_types = 1); namespace applistener; use thinkswooleWebsocket; class WsTest {     /**      * 事件監聽處理      *      * @return mixed      */     public function handle($event,Websocket $ws) {         //獲取當前發送消息客戶端的 fd         var_dump($ws ->?getSender()); ????????//發送廣播消息 ????????$ws?-&gt;?broadcast()?-&gt;?emit('testcallback',$event['message']); ????} }

$ws -> broadcast() 方法就是發送廣播消息。

但是如果想自己也收到廣播消息,那就需要增加一條 $ws -> to($ws -> getSender()) -> emit(‘testcallback’,$event[‘message’]); 即可。

模擬客戶端給另一個客戶端發消息

假設我當前 fd 為 1,但是我要模擬 用 fd 為 2 的客戶端給 fd 為 3 的客戶端發送消息,只需設置發送者 fd 和接收者兩個 fd 即可:

$ws?-&gt;?setSender(2)?-&gt;?to(3)?-&gt;?emit('testcallback',$event['message']);

經測試,1 沒有收到消息,2 和 3 都收到了。

獲取 SwooleWebSocketServer

假設說我們現在需要一個功能,判斷一個客戶端是否為有效客戶端,即是否與服務端握手成功。Think-Swoole 擴展中沒有這個功能,但是查閱 Swoole 官方文檔,有個 isEstablished 函數可以完成我們需要的功能,那么怎樣通過 Think-Swoole 拿到原生 Swoole 函數呢,答案就是獲取 SwooleWebSocketServer 這個類。有兩種方式:

1、app(‘swoole.server’);

2、app(‘thinkswooleManager’) -> getServer();

實例化后,就可以調用 Swoole 原生方法了,如:

$manager?=?app('thinkswooleManager'); $manager?-&gt;?getServer()?-&gt;?isEstablished(2);

附:thinkSwooleWebsocket類對象方法:

  • broadcast 設置進行廣播消息發送

  • isBroadcast 判斷當前是否是廣播模式

  • to 設置收件人 fd 或聊天室名(可以數組設置多個)

  • getTo 獲取收件人 fd 或聊天室名

  • join 當前客戶端加入到指定聊天室(可以多個)

  • leave 當前客戶端離開指定聊天室(可以多個)

  • emit 消息發送

  • close 關閉當前連接

  • getSender 獲取當前客戶端 id(即fd)

  • setSender 設置發件人的 fd

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享