多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
- think-swoole扩展的websocket均可为监听事件!!! - 创建一个监听类,在项目根目录下执行: ~~~ php think make:listener WebSocketEvent ~~~ 在`swoole.php`的`websocket['subscribe']`写入监听 ~~~ 'subscribe' => [ app\listener\WebSocketEvent::class ], ~~~ - `listen`和`subscribe`是一个东西,一个以文件为单位,一个以组为单位.subscribe的方法必须以`on`开头详见官方文档. - 特别说明:`onOpen`触发的事件名为`connect`并非`open`. - 其它详细细则,写在`WebsocketEvent.php`结合代码说明. <details> <summary>WebsocketEvent.php</summary> ~~~ <?php declare (strict_types=1); namespace app\listener; use app\Request; use Swoole\Server; use think\Container; use think\swoole\Table; use think\swoole\Websocket; class WebSocketEvent { protected $websocket = null; protected $server = null; protected $table = null; protected $u2fd = null; protected $fd2u = null; /** * WebSocketEvent constructor. * @param Server $server server对象 * @param Websocket $websocket websocket对线 * @param Container $container 容器 */ public function __construct(Server $server, Websocket $websocket, Container $container) { //这里取对象的方式有很多种,看个人习惯,在此列举其中几种方式 $this->websocket = $websocket;//依赖注入的方式 $this->server = $server; //think\table对象 $this->table = $container->get(Table::class);//从容器中取 //在think\Table的配置章节配置了两个table,使用方式如下 //vendor\topthink\think-swoole\src\Table.php实现了__get魔术方法,因此直接table->表即可使用 //或者table->get(表名)取得该表 $this->u2fd = $this->table->u2fd; $this->fd2u = $this->table->fd2u; } public function onConnect(Request $request) { //onOpen触发的事件,传入的是一个request对象 //模拟产生一个用户编号 $uid = rand(100, 999); //将uid与fd用table进行关联,set方法的key必须为string类型 //通过websocket的上下文取得fd:$this->websocket->getSender() $this->table->u2fd->set((string)$uid, ['fd' => $this->websocket->getSender()]); //将fd与uid用table进行关联 //注意传入数组的key必须与tables中的columns的name值相同,否则无法写入 $this->table->fd2u->set((string)$this->websocket->getSender(), ['uid' => $uid]); //这里是对所有的连接发送一次广播,消息为online,当前连接用户的uid,在线数量,当前连接用户的fd值 foreach ($this->table->u2fd as $row) { $this->server->push($row['fd'], json_encode(['msg' => 'online', 'uid' => $uid, 'online_count' => $this->u2fd->count(), 'fd' => $this->websocket->getSender()], 320)); } } public function onClose() { //onClose触发的事件 //将离线的用户从关系表中移除 $uid = $this->table->fd2u->get((string)$this->websocket->getSender(), 'uid'); //注意传入参数必须为string类型 $this->table->u2fd->del((string)$uid); $this->table->fd2u->del((string)$this->websocket->getSender()); //广播下线 foreach ($this->table->u2fd as $row) { $this->server->push($row['fd'], json_encode(['msg' => 'offline', 'uid' => $uid, 'online_count' => $this->u2fd->count(), 'fd' => $this->websocket->getSender()], 320)); } } public function onPoint($event) { //点对点消息 即json中event值为point会触发该方法 //json:{"event":"point","data":{"to":uid,"content":"wsmsg"}} //用uid从列表中查找该用户是否在线 $toFd = $this->table->u2fd->get((string)$event['to'], 'fd'); if ($toFd === false) { if (isset($event['api'])) { return 'offlone'; } $this->server->push($this->websocket->getSender(), $event['to'] . ' is not online'); } //判断是否来自api消息 if (isset($event['api'])) { //消息下放 $this->server->push($toFd, $this->assemblyData('point', ['sender' => $event['uid'] ?? 0, 'content' => $event['content']])); } else { //消息下放 $this->server->push($toFd, $this->assemblyData('point', ['sender' => $this->table->fd2u->get((string)$this->websocket->getSender(), 'uid'), 'content' => $event['content']])); } } public function onPing() { //响应ping消息 //{"event":"ping","data":""} $this->server->push($this->websocket->getSender(), $this->assemblyData('pong', [])); } //more event function //统一的消息格式 protected function assemblyData(string $event, array $data, int $code = 0): string { return json_encode(['event' => $event, 'data' => $data, 'code' => $code], 320); } } ~~~ </details>