zhamao-framework/components/http/websocket-access.html
2024-09-19 08:29:13 +00:00

126 lines
55 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>接入其他 WebSocket 客户端 | 炸毛框架 v3</title>
<meta name="description" content="">
<meta name="generator" content="VuePress 1.9.10">
<link rel="icon" href="/logo_trans.png">
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?f0f276cefa10aa31a20ae3815a50b795";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<meta name="description" content="一个高性能聊天机器人 + Web 框架">
<link rel="preload" href="/assets/css/0.styles.de075592.css" as="style"><link rel="preload" href="/assets/js/app.cf958133.js" as="script"><link rel="preload" href="/assets/js/2.4c04991c.js" as="script"><link rel="preload" href="/assets/js/1.d8755a39.js" as="script"><link rel="preload" href="/assets/js/38.75fa7a1c.js" as="script"><link rel="prefetch" href="/assets/js/10.960912c3.js"><link rel="prefetch" href="/assets/js/11.cd171694.js"><link rel="prefetch" href="/assets/js/12.ff9ca1d1.js"><link rel="prefetch" href="/assets/js/13.a56deac8.js"><link rel="prefetch" href="/assets/js/14.b222a011.js"><link rel="prefetch" href="/assets/js/15.31489867.js"><link rel="prefetch" href="/assets/js/16.e921dbc4.js"><link rel="prefetch" href="/assets/js/17.58f730d3.js"><link rel="prefetch" href="/assets/js/18.26c46c49.js"><link rel="prefetch" href="/assets/js/19.ee0bfd3b.js"><link rel="prefetch" href="/assets/js/20.bb3578b8.js"><link rel="prefetch" href="/assets/js/21.e66f7fe5.js"><link rel="prefetch" href="/assets/js/22.cba8ca48.js"><link rel="prefetch" href="/assets/js/23.cb49f41c.js"><link rel="prefetch" href="/assets/js/24.d95b175a.js"><link rel="prefetch" href="/assets/js/25.b0d69869.js"><link rel="prefetch" href="/assets/js/26.8e7089c0.js"><link rel="prefetch" href="/assets/js/27.333a53a1.js"><link rel="prefetch" href="/assets/js/28.df4b871c.js"><link rel="prefetch" href="/assets/js/29.5427ad45.js"><link rel="prefetch" href="/assets/js/3.07fc018e.js"><link rel="prefetch" href="/assets/js/30.7cb7445a.js"><link rel="prefetch" href="/assets/js/31.5c4bb546.js"><link rel="prefetch" href="/assets/js/32.7fc05474.js"><link rel="prefetch" href="/assets/js/33.9684a4f8.js"><link rel="prefetch" href="/assets/js/34.83e32a28.js"><link rel="prefetch" href="/assets/js/35.95d03df6.js"><link rel="prefetch" href="/assets/js/36.80aace42.js"><link rel="prefetch" href="/assets/js/37.1eaed2ee.js"><link rel="prefetch" href="/assets/js/39.117f5802.js"><link rel="prefetch" href="/assets/js/4.6623271b.js"><link rel="prefetch" href="/assets/js/40.57eba153.js"><link rel="prefetch" href="/assets/js/41.89c4a7c8.js"><link rel="prefetch" href="/assets/js/42.d8f92f99.js"><link rel="prefetch" href="/assets/js/43.5ee83631.js"><link rel="prefetch" href="/assets/js/44.c09b5b0c.js"><link rel="prefetch" href="/assets/js/45.bd850606.js"><link rel="prefetch" href="/assets/js/46.732b1cef.js"><link rel="prefetch" href="/assets/js/47.2a872d0d.js"><link rel="prefetch" href="/assets/js/48.959e18f4.js"><link rel="prefetch" href="/assets/js/49.a9bb32f7.js"><link rel="prefetch" href="/assets/js/5.073233e8.js"><link rel="prefetch" href="/assets/js/50.ca90a854.js"><link rel="prefetch" href="/assets/js/51.79142530.js"><link rel="prefetch" href="/assets/js/52.fe63ad16.js"><link rel="prefetch" href="/assets/js/53.ed84845a.js"><link rel="prefetch" href="/assets/js/54.3ab7e492.js"><link rel="prefetch" href="/assets/js/55.9028e407.js"><link rel="prefetch" href="/assets/js/56.8173f798.js"><link rel="prefetch" href="/assets/js/57.2166b068.js"><link rel="prefetch" href="/assets/js/58.7c52b6bf.js"><link rel="prefetch" href="/assets/js/59.e9965a7b.js"><link rel="prefetch" href="/assets/js/60.f277436c.js"><link rel="prefetch" href="/assets/js/61.3712f8fe.js"><link rel="prefetch" href="/assets/js/8.899a0731.js"><link rel="prefetch" href="/assets/js/9.e2e8da12.js"><link rel="prefetch" href="/assets/js/vendors~docsearch.303532f0.js">
<link rel="stylesheet" href="/assets/css/0.styles.de075592.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="ant-row"><div class="nav-button"><i aria-label="icon: bars" class="anticon anticon-bars"><svg viewBox="0 0 1024 1024" focusable="false" data-icon="bars" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M912 192H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM104 228a56 56 0 1 0 112 0 56 56 0 1 0-112 0zm0 284a56 56 0 1 0 112 0 56 56 0 1 0-112 0zm0 284a56 56 0 1 0 112 0 56 56 0 1 0-112 0z"></path></svg></i> <span></span></div> <div class="ant-col ant-col-xs-24 ant-col-sm-24 ant-col-md-6 ant-col-lg-6 ant-col-xl-5 ant-col-xxl-4"><a href="/" class="router-link-active home-link"><img src="/logo_trans.png" alt="炸毛框架 v3" class="logo"> <span class="site-name">炸毛框架 v3</span></a> <div class="search-box mobile-search"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div> <div class="nav-space-between ant-col ant-col-xs-0 ant-col-sm-0 ant-col-md-18 ant-col-lg-18 ant-col-xl-19 ant-col-xxl-20"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><ul role="menu" id="nav" class="ant-menu ant-menu-horizontal ant-menu-root ant-menu-light"><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/guide/">
指南
</a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/event/">
事件
</a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/components/bot/bot-context.html">
组件
</a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/plugins/management.html">
插件
</a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/advanced/">
进阶
</a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/update/v3.html">
更新日志
</a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="/doxy/" target="_blank">
API 文档
<i aria-label="icon: link" class="anticon anticon-link"><svg viewBox="64 64 896 896" focusable="false" data-icon="link" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M574 665.4a8.03 8.03 0 0 0-11.3 0L446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3l-39.8-39.8a8.03 8.03 0 0 0-11.3 0L191.4 526.5c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3L574 665.4zm258.6-474c-84.6-84.6-221.5-84.6-306 0L410.3 307.6a8.03 8.03 0 0 0 0 11.3l39.7 39.7c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204L665.3 562.6a8.03 8.03 0 0 0 0 11.3l39.8 39.8c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c84.5-84.6 84.5-221.5 0-306.1zM610.1 372.3a8.03 8.03 0 0 0-11.3 0L372.3 598.7a8.03 8.03 0 0 0 0 11.3l39.6 39.6c3.1 3.1 8.2 3.1 11.3 0l226.4-226.4c3.1-3.1 3.1-8.2 0-11.3l-39.5-39.6z"></path></svg></i></a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display:none;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li><li role="menuitem" class="ant-menu-item"><a href="https://docs-v2.zhamao.xin/" target="_blank">
炸毛框架 v2
<i aria-label="icon: link" class="anticon anticon-link"><svg viewBox="64 64 896 896" focusable="false" data-icon="link" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M574 665.4a8.03 8.03 0 0 0-11.3 0L446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3l-39.8-39.8a8.03 8.03 0 0 0-11.3 0L191.4 526.5c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3L574 665.4zm258.6-474c-84.6-84.6-221.5-84.6-306 0L410.3 307.6a8.03 8.03 0 0 0 0 11.3l39.7 39.7c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204L665.3 562.6a8.03 8.03 0 0 0 0 11.3l39.8 39.8c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c84.5-84.6 84.5-221.5 0-306.1zM610.1 372.3a8.03 8.03 0 0 0-11.3 0L372.3 598.7a8.03 8.03 0 0 0 0 11.3l39.6 39.6c3.1 3.1 8.2 3.1 11.3 0l226.4-226.4c3.1-3.1 3.1-8.2 0-11.3l-39.5-39.6z"></path></svg></i></a></li><li role="menuitem" class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="visibility:hidden;position:absolute;"><div aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div></li></ul> <ul class="extra-group"><li><a href="https://github.com/zhamao-robot/zhamao-framework" target="_blank" rel="noopener noreferrer" class="repo-link"><i aria-label="icon: github" class="anticon anticon-github"><svg viewBox="64 64 896 896" focusable="false" data-icon="github" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M511.6 76.3C264.3 76.2 64 276.4 64 523.5 64 718.9 189.3 885 363.8 946c23.5 5.9 19.9-10.8 19.9-22.2v-77.5c-135.7 15.9-141.2-73.9-150.3-88.9C215 726 171.5 718 184.5 703c30.9-15.9 62.4 4 98.9 57.9 26.4 39.1 77.9 32.5 104 26 5.7-23.5 17.9-44.5 34.7-60.8-140.6-25.2-199.2-111-199.2-213 0-49.5 16.3-95 48.3-131.7-20.4-60.5 1.9-112.3 4.9-120 58.1-5.2 118.5 41.6 123.2 45.3 33-8.9 70.7-13.6 112.9-13.6 42.4 0 80.2 4.9 113.5 13.9 11.3-8.6 67.3-48.8 121.3-43.9 2.9 7.7 24.7 58.3 5.5 118 32.4 36.8 48.9 82.7 48.9 132.3 0 102.2-59 188.1-200 212.9a127.5 127.5 0 0 1 38.1 91v112.5c.8 9 0 17.9 15 17.9 177.1-59.7 304.6-227 304.6-424.1 0-247.2-200.4-447.3-447.5-447.3z"></path></svg></i></a></li> <!----></ul></nav></div></div> <!----></header> <aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/components/" aria-current="page" title="组件" class="sidebar-link">组件</a></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>机器人组件</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>HTTP 组件</span> <span class="arrow down"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/components/http/zmrequest.html" title="ZMRequest HTTP 客户端" class="sidebar-link">ZMRequest HTTP 客户端</a></li><li><a href="/components/http/websocket-access.html" aria-current="page" title="接入其他 WebSocket 客户端" class="active sidebar-link">接入其他 WebSocket 客户端</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/components/http/websocket-access.html#接入" title="接入" class="sidebar-link">接入</a></li><li class="sidebar-sub-header"><a href="/components/http/websocket-access.html#接收和发送" title="接收和发送" class="sidebar-link">接收和发送</a></li><li class="sidebar-sub-header"><a href="/components/http/websocket-access.html#连接断开事件" title="连接断开事件" class="sidebar-link">连接断开事件</a></li><li class="sidebar-sub-header"><a href="/components/http/websocket-access.html#消息帧" title="消息帧" class="sidebar-link">消息帧</a></li><li class="sidebar-sub-header"><a href="/components/http/websocket-access.html#事件外主动发送消息帧" title="事件外主动发送消息帧" class="sidebar-link">事件外主动发送消息帧</a></li><li class="sidebar-sub-header"><a href="/components/http/websocket-access.html#多服务器端口" title="多服务器端口" class="sidebar-link">多服务器端口</a></li></ul></li><li><a href="/components/http/websocket-client.html" title="框架内置 WebSocket 客户端" class="sidebar-link">框架内置 WebSocket 客户端</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>框架通用组件</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>存储组件</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>依赖注入组件</span> <span class="arrow right"><i aria-label="icon: down" class="anticon anticon-down"><svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></p> <!----></section></li></ul> </aside> <main class="page has-page-anchor"> <div class="theme-antdocs-content content__default"><h1 id="接入其他-websocket-客户端"><a href="#接入其他-websocket-客户端" class="header-anchor">#</a> 接入其他 WebSocket 客户端</h1> <p>众所周知,炸毛框架提供了 HTTP、WebSocket 服务器功能,但默认的框架只接收 HTTP 请求和 OneBot 12 标准 的 WebSocket 客户端。</p> <p>想要接入其他 WebSocket 客户端,例如通过浏览器前端、游戏客户端、手机移动端等方式通过 WebSocket 接入框架从而和机器人实现联动,也是很容易的。</p> <h2 id="接入"><a href="#接入" class="header-anchor">#</a> 接入</h2> <p>框架默认只会接入 <code>Sec-WebSocket-Protocol</code><code>12.xxx</code> 类型的 WS 客户端,同时默认也会断掉所有未设置连接状态信息的 WebSocket 客户端握手请求。</p> <p>所以接入框架只需要写一个 <code>WebSocketOpenEvent</code> 的监听事件,在函数内通过 <code>ConnectionUtil::setConnection()</code> 方法标记该连接有效,框架就不会断掉连接,并保存该连接的信息。</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">BindEvent</span><span class="token punctuation">(</span><span class="token attribute-class-name class-name">WebSocketOpenEvent</span><span class="token operator">::</span><span class="token constant">class</span><span class="token punctuation">)</span></span><span class="token delimiter punctuation">]</span></span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">onCustomOpen</span><span class="token punctuation">(</span><span class="token class-name type-declaration">WebSocketOpenEvent</span> <span class="token variable">$event</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">// 例如通过判断 Sec-WebSocket-Protocol 头来识别一个第三方客户端类型</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">getHeaderLine</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Sec-WebSocket-Protocol'</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'my-custom-ws-client'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>ZM<span class="token punctuation">\</span>Utils<span class="token punctuation">\</span>ConnectionUtil</span><span class="token operator">::</span><span class="token function">setConnection</span><span class="token punctuation">(</span><span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getFd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'my-custom-ws-client'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'123'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 如果你的客户端要求握手回包中必须返回一个合法的 Sec-WebSocket-Protocol 头,则可以使用下面这行代码来添加额外的 Response Header</span>
<span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">withResponse</span><span class="token punctuation">(</span><span class="token function">zm_http_response</span><span class="token punctuation">(</span><span class="token argument-name">status_code</span><span class="token punctuation">:</span> <span class="token number">101</span><span class="token punctuation">,</span> <span class="token argument-name">headers</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'Sec-WebSocket-Protocol'</span> <span class="token operator">=&gt;</span> <span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">getHeaderLine</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Sec-WebSocket-Protocol'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>上方的例子的 <code>setConnection</code> 第二个参数是一个数组,你可以设置一些自己的键名和键值传入,用于保存该连接对应的信息,此后可以通过 <code>ConnectionUtil::getConnection($fd)</code> 方式获取。</p> <h2 id="接收和发送"><a href="#接收和发送" class="header-anchor">#</a> 接收和发送</h2> <p>接入后,你可以通过 <code>WebSocketMessageEvent</code> 来监听客户端发来的消息帧。当然,这里你需要用到一个内置的中间件,用于限定事件只获取指定类型的事件:</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">BindEvent</span><span class="token punctuation">(</span><span class="token attribute-class-name class-name">WebSocketMessageEvent</span><span class="token operator">::</span><span class="token constant">class</span><span class="token punctuation">)</span></span><span class="token delimiter punctuation">]</span></span>
<span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">Middleware</span><span class="token punctuation">(</span><span class="token attribute-class-name class-name">WebSocketFilter</span><span class="token operator">::</span><span class="token constant">class</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'my-custom-ws-client'</span> <span class="token operator">=&gt;</span> <span class="token attribute-class-name class-name">true</span><span class="token punctuation">]</span><span class="token punctuation">)</span></span><span class="token delimiter punctuation">]</span></span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">onCustomMessage</span><span class="token punctuation">(</span><span class="token class-name type-declaration">WebSocketMessageEvent</span> <span class="token variable">$event</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">FrameInterface</span> <span class="token variable">$frame</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">logger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'收到了自定义 ws 客户端发来的消息事件:'</span> <span class="token operator">.</span> <span class="token variable">$frame</span><span class="token operator">-&gt;</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>这里要注意,这个中间件 <code>WebSocketFilter</code> 的后面数组内为限定查询的参数。这个限定列表支持多个参数,键名为你在 <code>WebSocketOpenEvent</code> 中通过 <code>setConnection()</code> 方法添加的连接信息。</p> <p>这里的例子和上方形成了联动,比如这里使用 <code>['my-custom-ws-client' =&gt; true]</code> 的含义就是:
只要收到的 WebSocket 消息事件所属连接信息存在 <code>my-custom-ws-client</code> 字段,即为真,否则为假(不响应此事件)。</p> <blockquote><p>如果你不使用 <code>WebSocketFilter</code> 中间件做过滤,那么该 BindEvent 绑定的函数将响应所有类型的客户端连接的所有消息帧。</p></blockquote> <p>收到消息后,我们也可以使用 <code>$event-&gt;send()</code> 方法发送消息帧到客户端:</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'hello world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 传入字符串时,将自动转换为发送 UTF-8 文本的消息帧</span>
<span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Choir<span class="token punctuation">\</span>WebSocket<span class="token punctuation">\</span>FrameFactory</span><span class="token operator">::</span><span class="token function">createTextFrame</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'ohuo'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 你也可以直接传入一个符合 FrameInterface 接口的消息帧</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h2 id="连接断开事件"><a href="#连接断开事件" class="header-anchor">#</a> 连接断开事件</h2> <p>如果客户端主动断开与服务端的连接,服务端会触发 WebSocketCloseEvent 事件,同时伴随一个关闭帧。</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">BindEvent</span><span class="token punctuation">(</span><span class="token attribute-class-name class-name">WebSocketCloseEvent</span><span class="token operator">::</span><span class="token constant">class</span><span class="token punctuation">)</span></span><span class="token delimiter punctuation">]</span></span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">onClose</span><span class="token punctuation">(</span><span class="token class-name type-declaration">WebSocketCloseEvent</span> <span class="token variable">$event</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">logger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'fd '</span> <span class="token operator">.</span> <span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getFd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">' 关闭了连接'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h2 id="消息帧"><a href="#消息帧" class="header-anchor">#</a> 消息帧</h2> <p>WebSocket 通信少不了一个概念:消息帧。框架采用了 Choir 的 HTTP 组件,内包含一个 FrameInterface消息帧的接口类型。
框架支持发送所有实现了 FrameInterface 的消息帧,例如发送 PING 包、PONG 包、二进制数据包、UTF-8 文本包。</p> <p>框架默认使用的消息帧对象是:<code>\Choir\WebSocket\Frame</code>,你可以使用 FrameFactory 工厂类创建一个 Frame</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token variable">$frame</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Choir<span class="token punctuation">\</span>WebSocket<span class="token punctuation">\</span>FrameFactory</span><span class="token operator">::</span><span class="token function">createTextFrame</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 创建文本帧</span>
<span class="token variable">$frame</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Choir<span class="token punctuation">\</span>WebSocket<span class="token punctuation">\</span>FrameFactory</span><span class="token operator">::</span><span class="token function">createBinaryFrame</span><span class="token punctuation">(</span><span class="token function">file_get_contents</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'a.jpg'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 创建二进制数据帧</span>
<span class="token variable">$frame</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Choir<span class="token punctuation">\</span>WebSocket<span class="token punctuation">\</span>FrameFactory</span><span class="token operator">::</span><span class="token function">createPingFrame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 创建 ping 帧</span>
<span class="token variable">$frame</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Choir<span class="token punctuation">\</span>WebSocket<span class="token punctuation">\</span>FrameFactory</span><span class="token operator">::</span><span class="token function">createPongFrame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 创建 pong 帧</span>
<span class="token variable">$frame</span> <span class="token operator">=</span> <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Choir<span class="token punctuation">\</span>WebSocket<span class="token punctuation">\</span>FrameFactory</span><span class="token operator">::</span><span class="token function">createCloseFrame</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 创建关闭请求帧,用于主动正常断开 WebSocket 连接,参数为 WebSocket 的状态码,可参考 RFC</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h2 id="事件外主动发送消息帧"><a href="#事件外主动发送消息帧" class="header-anchor">#</a> 事件外主动发送消息帧</h2> <p>在使用 WebSocket 接入客户端时,往往会有不在事件内需要向已连接的客户端发送 WebSocket 消息的情况,框架的 Driver 层抽象了全局方法 <code>ws_socket()</code> 来提供一个可在事件外发送 WS 消息的功能。</p> <p>举例一,我们想在收到一个 HTTP 请求时,发送一条消息到所有已连接的同一类型 WebSocket 客户端。我们在接入客户端的时候,对客户端的 fd 做了缓存:</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">BindEvent</span><span class="token punctuation">(</span><span class="token attribute-class-name class-name">WebSocketOpenEvent</span><span class="token operator">::</span><span class="token constant">class</span><span class="token punctuation">)</span></span><span class="token delimiter punctuation">]</span></span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">onWSOpen</span><span class="token punctuation">(</span><span class="token class-name type-declaration">WebSocketOpenEvent</span> <span class="token variable">$event</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">getHeaderLine</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Sec-WebSocket-Protocol'</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string single-quoted-string">'special-app'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">logger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'special-app 已接入,正在鉴权'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 为了更贴近真实开发案例,这里假装通过 GET 请求传入的 token 参数进行一个鉴权,实际业务的鉴权逻辑请自行编写!</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">getQueryParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'token'</span><span class="token punctuation">]</span> <span class="token operator">??</span> <span class="token constant">null</span><span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token string single-quoted-string">'emhhbWFvLWZyYW1ld29yaw=='</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">logger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">warning</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'客户端 ['</span> <span class="token operator">.</span> <span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getFd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'] 鉴权失败'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">logger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'鉴权成功!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>ZM<span class="token punctuation">\</span>Utils<span class="token punctuation">\</span>ConnectionUtil</span><span class="token operator">::</span><span class="token function">setConnection</span><span class="token punctuation">(</span><span class="token variable">$event</span><span class="token operator">-&gt;</span><span class="token function">getFd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'special-app'</span> <span class="token operator">=&gt;</span> <span class="token function">time</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">Route</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/ws-test/{name}'</span><span class="token punctuation">)</span></span><span class="token delimiter punctuation">]</span></span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">onRouteTest</span><span class="token punctuation">(</span><span class="token keyword type-hint">array</span> <span class="token variable">$params</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token comment">// 这行的 ws_socket 传入的参数 1 为多 server 对应的 flag 参数,留空则默认使用 1。框架的默认配置第一个 websocket 的 flag 也是 1</span>
<span class="token comment">// sendMultiple 的作用在于同时到多个客户端,第二个参数是一个回调函数,可以用它来过滤选择自己相应连接</span>
<span class="token function">ws_socket</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">sendMultiple</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'收到了网页请求,它说它是 '</span> <span class="token operator">.</span> <span class="token variable">$params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">fn</span> <span class="token punctuation">(</span><span class="token variable">$fd</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">isset</span><span class="token punctuation">(</span><span class="token class-name static-context">ConnectionUtil</span><span class="token operator">::</span><span class="token function">getConnection</span><span class="token punctuation">(</span><span class="token variable">$fd</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'special-app'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 创建一个 HTTP Response 返回用户网页</span>
<span class="token keyword">return</span> <span class="token function">zm_http_response</span><span class="token punctuation">(</span><span class="token argument-name">body</span><span class="token punctuation">:</span> <span class="token string single-quoted-string">'hello, '</span> <span class="token operator">.</span> <span class="token variable">$params</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'name'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><p>除此之外,你也可以使用 <code>ws_socket()-&gt;send()</code> 方法,只给一个客户端发送消息帧,通过指定第二个参数 fd 来实现:</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token function">ws_socket</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">-&gt;</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'hello'</span><span class="token punctuation">,</span> <span class="token variable">$fd</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>另外,对于开发上的考虑,对于在事件外挑选一个客户端发送消息时,涉及 fd 存储的问题,你可以配合 <code>kv()</code><code>db()</code> 等组件对 fd 进行缓存。</p> <h2 id="多服务器端口"><a href="#多服务器端口" class="header-anchor">#</a> 多服务器端口</h2> <p>框架 3.0 支持了同时监听多个端口,例如框架默认的配置就同时监听了 20001、20002 分别做 WebSocket 服务端和 HTTP 服务端。你也可以继续让框架添加多个端口进行监听。</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token comment">// global.php</span>
<span class="token comment">/* 要启动的服务器监听端口及协议 */</span>
<span class="token variable">$config</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'servers'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
<span class="token punctuation">[</span>
<span class="token string single-quoted-string">'host'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'0.0.0.0'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'port'</span> <span class="token operator">=&gt;</span> <span class="token number">20001</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'type'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'websocket'</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">[</span>
<span class="token string single-quoted-string">'host'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'0.0.0.0'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'port'</span> <span class="token operator">=&gt;</span> <span class="token number">20002</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'type'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'http'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'flag'</span> <span class="token operator">=&gt;</span> <span class="token number">20002</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">[</span>
<span class="token string single-quoted-string">'host'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'0.0.0.0'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'port'</span> <span class="token operator">=&gt;</span> <span class="token number">20003</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'type'</span> <span class="token operator">=&gt;</span> <span class="token string single-quoted-string">'websocket'</span><span class="token punctuation">,</span>
<span class="token string single-quoted-string">'flag'</span> <span class="token operator">=&gt;</span> <span class="token number">4</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><p>每个服务端支持四个参数,<code>host</code><code>port</code><code>type</code><code>flag</code>。其中 flag 参数可忽略,忽略则默认值为 1。</p> <p>flag 的用处就是在事件内区分来源服务监听的端口,例如上方的配置,我监听了两个 websocket 的端口,第一个 flag 是 1第二个 flag 是 4。</p> <p>我们在 WebSocket 的三种事件WebSocketOpenEvent、WebSocketMessageEvent、WebSocketCloseEvent均可使用 WebSocketFilter 中间件进行过滤限定 flag。
下方为一个 Open 事件使用 Filter 过滤端口 20003 来源的客户端连接:</p> <div class="language-php line-numbers-mode"><pre class="language-php"><code><span class="token attribute"><span class="token delimiter punctuation">#[</span><span class="token attribute-content"><span class="token attribute-class-name class-name">BindEvent</span><span class="token punctuation">(</span><span class="token attribute-class-name class-name">WebSocketOpenEvent</span><span class="token operator">::</span><span class="token constant">class</span><span class="token punctuation">)</span></span><span class="token delimiter punctuation">]</span></span>
#<span class="token punctuation">[</span><span class="token function">Middleware</span><span class="token punctuation">(</span><span class="token class-name static-context">WebSocketFilter</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'flag'</span> <span class="token operator">=&gt;</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div></div> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/zhamao-robot/zhamao-framework/edit/main/docs/components/http/websocket-access.md" target="_blank" rel="noopener noreferrer">Edit this page</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----></footer> <div class="page-nav"><p class="inner"><span class="prev"><a href="/components/http/zmrequest.html" class="prev"><i aria-label="icon: left" class="anticon anticon-left"><svg viewBox="64 64 896 896" focusable="false" data-icon="left" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 0 0 0 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"></path></svg></i>
ZMRequest HTTP 客户端
</a></span> <span class="next"><a href="/components/http/websocket-client.html">
框架内置 WebSocket 客户端
<i aria-label="icon: right" class="anticon anticon-right"><svg viewBox="64 64 896 896" focusable="false" data-icon="right" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M765.7 486.8L314.9 134.7A7.97 7.97 0 0 0 302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 0 0 0-50.4z"></path></svg></i></a></span></p></div> <div class="page-anchor"><div class="ant-space ant-space-vertical" style="width:100%;"><div class="ant-space-item"><div class="page-anchor-offset"><div><div class="ant-anchor-wrapper" style="max-height:100vh;"><div class="ant-anchor"><div class="ant-anchor-ink"><span class="ant-anchor-ink-ball"></span></div><div class="ant-anchor-link"><a href="#接入" title="接入" class="ant-anchor-link-title">接入</a></div><div class="ant-anchor-link"><a href="#接收和发送" title="接收和发送" class="ant-anchor-link-title">接收和发送</a></div><div class="ant-anchor-link"><a href="#连接断开事件" title="连接断开事件" class="ant-anchor-link-title">连接断开事件</a></div><div class="ant-anchor-link"><a href="#消息帧" title="消息帧" class="ant-anchor-link-title">消息帧</a></div><div class="ant-anchor-link"><a href="#事件外主动发送消息帧" title="事件外主动发送消息帧" class="ant-anchor-link-title">事件外主动发送消息帧</a></div><div class="ant-anchor-link"><a href="#多服务器端口" title="多服务器端口" class="ant-anchor-link-title">多服务器端口</a></div></div></div></div></div></div></div></div> </main> <!----></div><div class="global-ui"></div></div>
<script src="/assets/js/app.cf958133.js" defer></script><script src="/assets/js/2.4c04991c.js" defer></script><script src="/assets/js/1.d8755a39.js" defer></script><script src="/assets/js/38.75fa7a1c.js" defer></script>
</body>
</html>