swoft 提供了灵活的 websocket 使用,支持自定义和由框架托管处理消息两种方式。
如果你在 ws 模块类没有添加 @OnMessage 处理方法,框架将会自动托管这个阶段,解析消息并根据路由分发到不同的方法执行 如果你在 ws 模块类里面绑定了 @OnMessage 处理方法,swoft 就认为你想自己处理这个阶段,框架就不会处理了
定义 ws 模块
<?php declare(strict_types=1);
namespace AppWebSocket;
use AppWebSocketChatHomeController;
use SwoftHttpMessageRequest;
use SwoftWebSocketServerAnnotationMappingOnOpen;
use SwoftWebSocketServerAnnotationMappingWsModule;
use SwoftWebSocketServerMessageParserJsonParser;
use function server;
/**
* Class ChatModule
*
* @WsModule(
* "/chat",
* messageParser=JsonParser::class,
* controllers={HomeController::class}
* )
*/
class ChatModule
{
/**
* @OnOpen()
* @param Request $request
* @param int $fd
*/
public function onOpen(Request $request, int $fd): void
{
server()->push($request->getFd(), "Opened, welcome!(FD: $fd)");
}
}
上面代码注解增加了 messageParser 和 controllers 将消息处理转发给控制器处理
消息解析器
不同的使用者或者使用场景,用于 ws 通信的数据格式可能是不一样的。因此,在编写 ws 模块时,需要你绑定消息解析器。
内置解析器
- SwoftWebSocketServerMessageParserRawTextParser 简单的字符串
- SwoftWebSocketServerMessageParserTokenTextParser 简单的 token 字符串协议(方便测试使用的)
- SwoftWebSocketServerMessageParserJsonParser 简单的 JSON 数据协议
推荐使用JSON的解析格式
JSON 协议通信数据结构:
{
"cmd": "home.index", // type: string,
"data": "我是要发送的数据", // type: mixed(array|string|int)
"ext": {"ip": "127.0.0.1", "os": "mac"}, // optional, type: array
}
说明
- cmd 控制器的前缀和路由的名称组合,中间通过点连接,必须这样写,不然解析不到具体的控制器中.
- data 客户端发送给服务器的数据 通过
$req = context()->getRequest(); $msg=$req->getMessage();$msg->getData()
可以获取到数据 - ext 客户端发送的额外信息 通过
$req = context()->getRequest();$req->getExt();
可以得到数据
客户端调用代码示例
const wsUrl = 'ws://127.0.0.1:18308/chat'
let ws = new WebSocket(wsUrl)
const req={cmd:"home.index",data:"我是客户端数据",ext:[]}
ws.send(JSON.stringify(req))
获取数据
use SwoftWebSocketServerMessageRequest;
$req = context()->getRequest();
$msg = $req->getMessage();
$data = $msg->getData();
$fd = $req-getFd();
$ext = $req->getExt();
控制器定义
<?php declare(strict_types=1);
namespace AppWebSocketChat;
use SwoftSessionSession;
use SwoftWebSocketServerAnnotationMappingMessageMapping;
use SwoftWebSocketServerAnnotationMappingWsController;
/**
* Class HomeController
*
* @WsController(prefix="home")
*/
class HomeController
{
/**
* Message command is: 'home.index'
*
* @return void
* @MessageMapping(command="index")
*/
public function index(): void
{
Session::mustGet()->push('hi, this is home.index');
}
}
代码详解
注解
@WsController 注解
websocket 消息控制器注解 @WsController
类似于 http 中的 controller
注解类:SwoftWebSocketServerAnnotationMappingWsController
作用范围:CLASS
拥有属性:
- prefix string 消息路由前缀
@MessageMapping 注解
方法注解 @MessageMapping 标记具体的消息处理方法,类似于 http 控制器里的 action。
类似于 http 中的 RequestMapping
注解类:SwoftWebSocketServerAnnotationMappingMessageMapping
作用范围:METHOD
拥有属性:
command string 消息命令名称
完整的消息路由 path 是 上面的 preifx 和 command 由点拼接而成 PREFIX.COMMAND
推荐显示的指定 @WsController 注解的 prefix 和 @MessageMapping 注解的 command
消息发送 API
注意下面的方法都在类:SwoftWebSocketServerWebSocketServer
发送给某个客户端
public function sendTo(int $receiver, string $data, int $sender = 0): int
参数说明:
- $receiver int 接收者的 fd
- $data string 要发送的消息数据
- $sender int 发送者的 fd。 可选的
示例
server()->sendTo($fd, 'hi, 你好啊!');
发送给指定的一些客户端
public function sendToSome(string $data, array $receivers = [], array $excluded = [], int $sender = 0, int $pageSize = 50): int
参数说明:
- $data string 要发送的消息数据
- $receivers int[] 指定的接收者 fd 列表
- $excluded int[] 排除的接收者 fd 列表
- $sender int 发送者的 fd。 可选的
方法说明:
- 当 $receivers 有数据时,将会忽略 $excluded。 此时就是将消息指定的发给这些接收者
- 当 $receivers 为空时
- 若 $excluded 有值,将会给除了这些人之外的发送消息
- 若 $excluded 为空,相当于给所有人发消息
示例
server()->sendToSome('hi, 你们好啊!', [$fd0, $fd1, ...]);
广播消息
public function sendToAll(string $data, int $sender = 0, int $pageSize = 50): int
发送消息给所有客户端,相当于进行全员广播。使用分页方式发送,每 50 个一页,直到全部发送完毕。
参数说明:
- $data string 要发送的消息数据
- $sender int 发送者的 fd。 可选的
示例
server()->sendToAll('hi, 大家好啊!');
断开连接
server()->disconnect($fd);
以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要
PHP进阶架构师>>>视频、面试文档免费获取shimo.im![d25343a15b85d473161236a3308bbd67.png](https://img-blog.csdnimg.cn/img_convert/d25343a15b85d473161236a3308bbd67.png)
或 者关注咱们下面的知乎专栏
PHP架构师圈子zhuanlan.zhihu.com![33c2d1faf43f29cc929b1e98f2d5cbc7.png](https://img-blog.csdnimg.cn/img_convert/33c2d1faf43f29cc929b1e98f2d5cbc7.png)