视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Think-Swoole之WebSocket消息、广播以及 Swoole 原生方法调用
2020-11-02 18:02:00 责编:小采
文档
Think-Swoole 教程之WebSocket 消息、广播以及 Swoole 原生方法调用

什么是客户端的 fd

fd 是在 Swoole 中客户端的唯一标识符,fd 是复用的,当连接关闭后 fd 会被新进入的连接复用,正在维持的 TCP 连接 fd 不会被复用。

获取当前客户端的fd

app/listener/WsConnect.php

<?php
declare (strict_types = 1);
namespace applistener;
use 	hinkswooleWebsocket;
class WsTest
{
 /**
 * 事件监听处理
 *
 * @return mixed
 */
 public function handle($event,Websocket $ws)
{
// $ws = app('thinkswooleWebsocket'); // 单例
 //获取当前发送消息客户端的 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 applistener;
use 	hinkswooleWebsocket;
class WsTest
{
 /**
 * 事件监听处理
 *
 * @return mixed
 */
 public function handle($event,Websocket $ws)
{
// $ws = app('thinkswooleWebsocket'); // 单例
 //获取当前发送消息客户端的 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 applistener;
use 	hinkswooleWebsocket;
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 都收到了。

获取 SwooleWebSocketServer

假设说我们现在需要一个功能,判断一个客户端是否为有效客户端,即是否与服务端握手成功。Think-Swoole 扩展中没有这个功能,但是查阅 Swoole 官方文档,有个 isEstablished 函数可以完成我们需要的功能,那么怎样通过 Think-Swoole 拿到原生 Swoole 函数呢,答案就是获取 SwooleWebSocketServer 这个类。有两种方式:

1、app('swoole.server');

2、app('thinkswooleManager') -> getServer();

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

$manager = app('thinkswooleManager');
$manager -> getServer() -> isEstablished(2);

附: hinkSwooleWebsocket类对象方法:

  • broadcast 设置进行广播消息发送

  • isBroadcast 判断当前是否是广播模式

  • to 设置收件人 fd 或聊天室名(可以数组设置多个)

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

  • join 当前客户端加入到指定聊天室(可以多个)

  • leave 当前客户端离开指定聊天室(可以多个)

  • emit 消息发送

  • close 关闭当前连接

  • getSender 获取当前客户端 id(即fd)

  • setSender 设置发件人的 fd

  • 下载本文
    显示全文
    专题