Think-Swoole 教程之WebSocket 訊息、廣播以及Swoole 原生方法呼叫
什麼是客戶端的fd
fd 是在Swoole 中客戶端的唯一識別符,fd 是複用的,當連線關閉後fd 會被新進入的連線複用,正在維持的TCP 連線fd 不會被重複使用。
取得目前客戶端的fd
app/listener/WsConnect.php
<?php declare (strict_types = 1); namespace app\listener; use \think\swoole\Websocket; class WsTest { /** * 事件监听处理 * * @return mixed */ public function handle($event,Websocket $ws) { // $ws = app('think\swoole\Websocket'); // 单例 //获取当前发送消息客户端的 fd var_dump($ws -> getSender()); } }
test.html
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> 消息:<input type="text" id="message"> 接收者:<input type="text" id="to"> <button onclick="send()">发送</button> <script> var ws = new WebSocket("ws://127.0.0.1:9501/"); ws.onopen = function(){ console.log('连接成功'); } ws.onmessage = function(data){ console.log(data.data); } ws.onclose = function(){ console.log('连接断开'); } function send() { var message = document.getElementById('message').value; var to = document.getElementById('to').value; console.log("准备给" + to + "发送数据:" + message); ws.send(JSON.stringify(['test',{ to:to, message:message }])); //发送的数据必须是 ['test',数据] 这种格式 } </script> </body> </html>
瀏覽器打開多個標籤,來模擬多個客戶端連接,均訪問test.html 文件,控制台將會列印每個客戶端的fd ,如下圖我們打開三個標籤進行訪問:
也就是說,服務端發送過來的訊息,都會被HTML 中的ws.onmessage 接收到。
給指定fd 的客戶端發送訊息(單發、群發)
app/listener/WsTest.php
<?php declare (strict_types = 1); namespace app\listener; use \think\swoole\Websocket; class WsTest { /** * 事件监听处理 * * @return mixed */ public function handle($event,Websocket $ws) { // $ws = app('think\swoole\Websocket'); // 单例 //获取当前发送消息客户端的 fd var_dump($ws -> getSender()); //发送给指定 fd 的客户端,包括发送者自己 $ws -> to(intval($event['to'])) -> 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 的客戶端:
發送後,可見只有fd 為1、2 的客戶端能收到訊息(也就是說訊息發出者本身也會收到訊息),而fd 為3 的客戶端卻沒有收到訊息:
發送後,可見只有fd 為1、2 的客戶端能收到訊息(也就是說訊息發出者本身也會收到訊息),而fd 為3 的客戶端卻沒有收到訊息:
發送廣播訊息
廣播訊息就是發送一條訊息給所有客戶端,但是不包括自己。
app/listener/WsConnect.php
<?php declare (strict_types = 1); namespace app\listener; use \think\swoole\Websocket; class WsTest { /** * 事件监听处理 * * @return mixed */ public function handle($event,Websocket $ws) { //获取当前发送消息客户端的 fd var_dump($ws -> getSender()); //发送广播消息 $ws -> broadcast() -> emit('testcallback',$event['message']); } }
$ws -> broadcast() 方法就是發送廣播訊息。
但如果想自己也收到廣播訊息,那就需要增加一條$ws -> to($ws -> getSender()) -> emit('testcallback',$event[' message']); 即可。
模擬客戶端給另一個客戶端發送訊息
假設我目前fd 為1,但是我要模擬用fd 為2 的客戶端給fd 為3 的客戶端發送訊息,只要設定發送者fd 和接收者兩個fd 即可:
$ws -> setSender(2) -> to(3) -> emit('testcallback',$event['message']);
經測試,1 沒有收到訊息,2 和3 都收到了。
取得 Swoole\WebSocket\Server
假設我們現在需要一個功能,判斷一個客戶端是否為有效客戶端,也就是是否與服務端握手成功。 Think-Swoole 擴充功能中沒有這個功能,但是查閱 Swoole 官方文檔,有個 isEstablished 函數可以完成我們需要的功能,那麼怎麼透過 Think-Swoole 拿到原生 Swoole 函數呢,答案就是取得 Swoole\WebSocket\Server 這個類別。有兩種方式:
1、app('swoole.server');
2、app('think\swoole\Manager') -> getServer();
實例化後,就可以呼叫Swoole 原生方法了,如:
$manager = app('think\swoole\Manager'); $manager -> getServer() -> isEstablished(2);
附:\think\Swoole\Websocket類別物件方法:
broadcast 設定進行廣播訊息傳送
isBroadcast 判斷目前是否為廣播模式
to 設定收件者fd 或聊天室名稱(可以陣列設定多個)
getTo 取得收件者fd 或聊天室名稱
#join 目前用戶端加入到指定聊天室(可以多個)
leave 當前客戶端離開指定聊天室(可以多個)
#emit 訊息發送
close 關閉目前連線
getSender 取得目前客戶端id(即fd)
setSender 設定寄件者的fd
以上是Think-Swoole之WebSocket訊息、廣播以及 Swoole 原生方法調用的詳細內容。更多資訊請關注PHP中文網其他相關文章!