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
Atas ialah kandungan terperinci Think-Swoole之WebSocket消息、广播以及 Swoole 原生方法调用. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!