☰
CRMEB 中的 Workerman 长连接服务:从异步网络编程到即时通讯实战
2026/10/15 1:52:59 网站建设 项目流程
  • 后端
  • 电商
  • 前端

【免费下载链接】CRMEB

🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

项目地址:https://gitcode.com/gh_mirrors/cr/CRMEB
点击查看免费下载

导读

本文以 CRMEB 仓库中内置的 Workerman 官方 README 为核心骨架,系统讲解 Workerman 异步事件驱动框架的环境要求、安装方式、六大服务搭建(WebSocket/HTTP/WebServer/TCP/SSL/自定义协议)、Timer 定时器、AsyncTcpConnection 异步连接以及 ReactPHP 生态集成,并结合 CRMEB 的think workerman命令、config/workerman.php配置与crmeb/services/workerman源码,说明后台管理员消息通知、H5 客服聊天、新订单弹窗等长连接场景的真实落地方式。读完你将掌握 Workerman 的完整入门到进阶用法,并能看懂 CRMEB 长连接服务的进程结构与消息分发链路。


一、Workerman 是什么:异步事件驱动的 PHP 网络框架

Workerman 是一个纯 PHP 实现的异步事件驱动网络框架,用于快速构建高性能、可扩展的网络应用。它不依赖 PHP-FPM/Nginx,而是自己常驻内存监听端口、处理并发连接,因此天然适合聊天、实时推送、在线客服、物联网网关等长连接场景。

在 CRMEB 项目中,Workerman 承担三类核心长连接职责(见 config/workerman.php 顶部注释):

  • channel(内部通讯):系统程序收到消息后,通过此端口推送给对应客户/客服,以及后台新订单弹窗提醒;
  • admin(后台通知):新订单、新退款单发送消息给程序,后台消息通知;
  • chat(客服聊天):客户或客服发送消息给程序,客服消息通知。

从依赖角度,当前仓库锁定的是 Workerman 3.5.19 版本(见 Worker.php 中的const VERSION = '3.5.19')。其内部结构分为四层:事件循环层(Workerman\Events,支持 Select/libevent/Event/Swoole/React 等)、连接层(Workerman\Connection)、协议层(Workerman\Protocols,内置 HTTP/WebSocket/Text/Frame)以及核心的 Worker.php 进程容器。

核心特性

  • 支持 HTTP、WebSocket、SSL 及任意自定义协议;
  • 支持多进程部署(count属性设置进程数),多进程间通过 Channel 组件通信;
  • 支持 libevent、HHVM、ReactPHP 等事件循环扩展;
  • 完全常驻内存,无 PHP 请求生命周期开销。

二、环境要求与安装

Workerman 官方 README 明确给出的运行前提如下:

项目要求
PHP 版本PHP 5.3 或更高
操作系统POSIX 兼容系统(Linux、macOS、BSD)
PHP 扩展POSIX 与 PCNTL 扩展

需要说明的是,这里“PHP 5.3+”是 Workerman 库自身的最低要求;而 CRMEB v5 后端运行环境要求PHP 7.1–7.4(见 crmeb/README.md),实际部署时以 CRMEB 的要求为准。

安装方式(Composer):

composer require workerman/workerman

当前仓库中该依赖已通过 Composer 安装至crmeb/vendor/workerman/workerman,其 composer.json 声明了 PSR-4 自动加载(Workerman\→./),并建议安装ext-event以获得更好的性能。若要使用 ReactPHP 生态,还需按需安装react/mysql、clue/redis-react、react/dns、react/http-client、react/zmq、react/stomp等包。

Windows 并非推荐运行环境:php think workerman start --d等守护进程模式依赖 POSIX 信号机制,在 Windows 下需要分三步分别启动内部通讯、admin、chat 三个服务(详见 crmeb/README.md)。

三、五种基础服务搭建实战

Workerman 统一以「协议 URI + 回调」的方式组织代码:new Worker("协议://监听地址:端口"),然后给实例挂上onConnect/onMessage/onClose等回调,最后调用Worker::runAll()启动。以下示例均可在独立start.php中直接运行。

1. WebSocket 服务器

<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // 创建 Websocket 服务器 $ws_worker = new Worker("websocket://0.0.0.0:2346"); // 4 个进程 $ws_worker->count = 4; // 新连接到来时触发 $ws_worker->onConnect = function($connection) { echo "New connection\n"; }; // 收到数据时触发 $ws_worker->onMessage = function($connection, $data) { // 给客户端回送 hello $data $connection->send('hello ' . $data); }; // 连接关闭时触发 $ws_worker->onClose = function($connection) { echo "Connection closed\n"; }; // 运行 Worker Worker::runAll();

要点解读:

  • count决定启动的子进程数,多进程可显著提升并发吞吐,但 CRMEB 中 admin/chat 均配置为1(见下文),因为需要依靠单进程内存中的$user映射表维护“用户 ID → 连接”关系;
  • 三个回调各自独立,对应 Worker.php 中onWorkerStart、onConnect、onMessage、onClose、onError、onBufferFull、onBufferDrain等公开属性(回调)。

2. HTTP 服务器

Workerman 的 HTTP 协议处理器会解析请求并填充 PHP 超全局变量,因此在onMessage中可以直接使用$_GET、$_POST、$_COOKIE、$_SESSION、$_SERVER、$_FILES:

require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // #### http worker #### $http_worker = new Worker("http://0.0.0.0:2345"); // 4 个进程 $http_worker->count = 4; // 收到数据时触发 $http_worker->onMessage = function($connection, $data) { var_dump($_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER, $_FILES); // 给客户端回送数据 $connection->send("hello world \n"); }; // 运行所有 worker Worker::runAll();

从源码看,Http.php 支持GET/POST/PUT/DELETE/HEAD/OPTIONS六种方法,input()负责判断请求是否完整(依据\r\n\r\n与Content-Length计算包长度),并校验包大小上限maxPackageSize,不合法请求直接返回400 Bad Request。

3. WebServer(静态网站服务器)

Workerman\WebServer是 Worker 的子类,基于 HTTP 协议封装了虚拟主机与静态文件服务能力:

require_once __DIR__ . '/vendor/autoload.php'; use Workerman\WebServer; use Workerman\Worker; // WebServer $web = new WebServer("http://0.0.0.0:80"); // 4 个进程 $web->count = 4; // 设置域名对应的站点根目录 $web->addRoot('www.your_domain.com', '/your/path/Web'); $web->addRoot('www.another_domain.com', '/another/path/Web'); // 运行所有 worker Worker::runAll();

从 WebServer.php 的实现可见:addRoot()将“域名 → 站点根目录”写入$serverRoot映射;进程启动时若映射为空会直接报错退出(server root not set),同时初始化mime.types表(见Protocols/Http/mime.types)。

4. TCP 服务器

最底层的 TCP 服务器是理解 Workerman 数据流的起点——所有上层协议(HTTP/WebSocket/Text)最终都是对 TCP 字节流的input/decode/encode拆包封包:

require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // #### 创建 socket 并监听 1234 端口 #### $tcp_worker = new Worker("tcp://0.0.0.0:1234"); // 4 个进程 $tcp_worker->count = 4; // 新连接到来时触发 $tcp_worker->onConnect = function($connection) { echo "New Connection\n"; }; // 收到数据时触发 $tcp_worker->onMessage = function($connection, $data) { $connection->send("hello $data \n"); }; // 连接关闭时触发 $tcp_worker->onClose = function($connection) { echo "Connection closed\n"; }; Worker::runAll();

5. 开启 SSL(wss:// / https://)

通过传入 stream context 再切换传输层transport = 'ssl',即可将服务升级为加密通道:

<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // SSL context $context = array( 'ssl' => array( 'local_cert' => '/your/path/of/server.pem', 'local_pk' => '/your/path/of/server.key', 'verify_peer' => false, ) ); // 创建带 SSL context 的 Websocket 服务器 $ws_worker = new Worker("websocket://0.0.0.0:2346", $context); // 启用 SSL。WebSocket+SSL 即 Secure WebSocket(wss://) // https 等也采用类似方式 $ws_worker->transport = 'ssl'; $ws_worker->onMessage = function($connection, $data) { $connection->send('hello ' . $data); }; Worker::runAll();

CRMEB 在 Workerman.php 命令 中完整复刻了这一模式:从系统配置读取证书文件路径(wssLocalCert/wssLocalpk),组装local_cert、local_pk、verify_peer => false的 SSL context,再按需设置transport = 'ssl'。当前仓库中wss_open被固定为0,即默认走明文 websocket,开启 WSS 需自行申请域名证书。

四、自定义协议:Text + "\n" 的完整范例

当内置协议不满足业务时,可以自定义协议。协议类只需实现三个静态方法,Workerman 会通过ProtocolInterface(见 Protocols/ProtocolInterface.php)调用它们:

  • input($recv_buffer):判断缓冲区中是否已有一个完整包,返回包长度;不足返回 0;
  • decode($recv_buffer):把原始字节解析为业务数据;
  • encode($data):把业务数据编码为发送字节流。

以下示例定义了一个「每包以\n结尾」的文本协议:

Protocols/MyTextProtocol.php

namespace Protocols; /** * 用户自定义协议 * 格式 Text+"\n" */ class MyTextProtocol { public static function input($recv_buffer) { // 查找 "\n" 首次出现的位置 $pos = strpos($recv_buffer, "\n"); // 尚未收到完整包,返回 0 表示无法计算包长度 if($pos === false) { return 0; } // 返回包长度 return $pos+1; } public static function decode($recv_buffer) { return trim($recv_buffer); } public static function encode($data) { return $data."\n"; } }

在 Worker 中以MyTextProtocol://前缀注册:

require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // #### MyTextProtocol worker #### $text_worker = new Worker("MyTextProtocol://0.0.0.0:5678"); $text_worker->onConnect = function($connection) { echo "New connection\n"; }; $text_worker->onMessage = function($connection, $data) { $connection->send("hello world \n"); }; $text_worker->onClose = function($connection) { echo "Connection closed\n"; }; // 运行所有 worker Worker::runAll();

与之对照,内置的 Websocket.php 的input()就是逐字节解析帧头(FIN、掩码、opcode、长度),握手未完成时进入dealHandshake,并校验客户端帧必须带掩码(frame not masked直接断开);Frame.php 则以 4 字节大端长度前缀拆包。理解这三个方法,就掌握了 Workerman 一切协议的底层逻辑。

五、Timer 定时器:进程内毫秒级任务调度

Timer 是 Workerman 内置的轻量定时器,适合做心跳检测、轮询清理等进程内任务:

require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; use Workerman\Lib\Timer; $task = new Worker(); $task->onWorkerStart = function($task) { // 间隔 2.5 秒 $time_interval = 2.5; $timer_id = Timer::add($time_interval, function() { echo "Timer run\n"; } ); }; // 运行所有 worker Worker::runAll();

源码层面(Lib/Timer.php):

  • Timer::add($time_interval, $func, $args = array(), $persistent = true),$persistent = false时仅执行一次(EV_TIMER_ONCE);
  • 未启用事件扩展时,基于pcntl_alarm(1)+SIGALRM信号驱动,每次 tick 将到期任务执行后按原间隔重新挂入任务表;
  • 启用 libevent/Event 等扩展时,直接委托给事件循环的EV_TIMER通道,精度更高;
  • Timer::del($timer_id)与Timer::delAll()用于移除定时任务。

CRMEB 中的 Timer 应用

  1. 心跳与超时检测:在 WorkermanService.php 与 ChatService.php 中,Timer::add(15, ...)每 15 秒扫描全部连接,若当前时间 - lastMessageTime > 12秒则判定掉线并close('timeout'),同时把在线状态写回数据库、广播给客服端。
  2. 在线状态刷新:ChatService每 2 秒统计在线用户与在线客服的 uid 集合,将不在线的记录批量置为online = 0(见 ChatService.php)。
  3. CRMEB 定时任务命令:php think timer start同样基于 Workerman 的 Worker 与 Timer 实现(见 crmeb/crmeb/command/Timer.php),在onWorkerStart中调用SystemCrontabServices::crontabCommandRun()执行平台配置的定时任务,支持-i 0.001自定义执行间隔,PID 文件写入runtime/timer.pid。

六、AsyncTcpConnection:异步客户端连接

AsyncTcpConnection让 Workerman 进程既能当服务器,也能当异步客户端,可主动连接外部 TCP/WebSocket 等服务:

require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; use Workerman\Connection\AsyncTcpConnection; $worker = new Worker(); $worker->onWorkerStart = function() { // 客户端使用 Websocket 协议 $ws_connection = new AsyncTcpConnection("ws://echo.websocket.org:80"); $ws_connection->onConnect = function($connection){ $connection->send('hello'); }; $ws_connection->onMessage = function($connection, $data){ echo "recv: $data\n"; }; $ws_connection->onError = function($connection, $code, $msg){ echo "error: $msg\n"; }; $ws_connection->onClose = function($connection){ echo "connection closed\n"; }; $ws_connection->connect(); }; Worker::runAll();

从源码看,AsyncTcpConnection.php 继承自TcpConnection,默认transport = 'tcp'、_remotePort = 80,需要显式调用connect()建立连接,并支持tcp/ws/text/frame等协议前缀。这一能力是 CRMEB Channel 组件通信的底层基础之一。

七、ReactPHP 生态集成

Workerman 的事件循环与 ReactPHP 完全兼容,可直接在onWorkerStart中通过Worker::getEventLoop()获取事件循环并创建异步客户端。官方 README 给出了六个组合示例。

1. 异步 MySQL

composer require react/mysql
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; $worker = new Worker('tcp://0.0.0.0:6161'); $worker->onWorkerStart = function() { global $mysql; $loop = Worker::getEventLoop(); $mysql = new React\MySQL\Connection($loop, array( 'host' => '127.0.0.1', 'dbname' => 'dbname', 'user' => 'user', 'passwd' => 'passwd', )); $mysql->on('error', function($e){ echo $e; }); $mysql->connect(function ($e) { if($e) { echo $e; } else { echo "connect success\n"; } }); }; $worker->onMessage = function($connection, $data) { global $mysql; $mysql->query('show databases', function ($command, $mysql) use ($connection) { if ($command->hasError()) { $error = $command->getError(); } else { $results = $command->resultRows; $fields = $command->resultFields; $connection->send(json_encode($results)); } }); }; Worker::runAll();

2. 异步 Redis

composer require clue/redis-react
<?php require_once __DIR__ . '/vendor/autoload.php'; use Clue\React\Redis\Factory; use Clue\React\Redis\Client; use Workerman\Worker; $worker = new Worker('tcp://0.0.0.0:6161'); $worker->onWorkerStart = function() { global $factory; $loop = Worker::getEventLoop(); $factory = new Factory($loop); }; $worker->onMessage = function($connection, $data) { global $factory; $factory->createClient('localhost:6379')->then(function (Client $client) use ($connection) { $client->set('greeting', 'Hello world'); $client->append('greeting', '!'); $client->get('greeting')->then(function ($greeting) use ($connection){ echo $greeting . PHP_EOL; $connection->send($greeting); }); $client->incr('invocation')->then(function ($n) use ($connection){ echo 'This is invocation #' . $n . PHP_EOL; $connection->send($n); }); }); }; Worker::runAll();

3. 异步 DNS 解析

composer require react/dns
require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; $worker = new Worker('tcp://0.0.0.0:6161'); $worker->onWorkerStart = function() { global $dns; $loop = Worker::getEventLoop(); $factory = new React\Dns\Resolver\Factory(); $dns = $factory->create('8.8.8.8', $loop); }; $worker->onMessage = function($connection, $host) { global $dns; $host = trim($host); $dns->resolve($host)->then(function($ip) use($host, $connection) { $connection->send("$host: $ip"); },function($e) use($host, $connection){ $connection->send("$host: {$e->getMessage()}"); }); }; Worker::runAll();

4. 异步 HTTP 客户端

composer require react/http-client
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; $worker = new Worker('tcp://0.0.0.0:6161'); $worker->onMessage = function($connection, $host) { $loop = Worker::getEventLoop(); $client = new \React\HttpClient\Client($loop); $request = $client->request('GET', trim($host)); $request->on('error', function(Exception $e) use ($connection) { $connection->send($e); }); $request->on('response', function ($response) use ($connection) { $response->on('data', function ($data) use ($connection) { $connection->send($data); }); }); $request->end(); }; Worker::runAll();

5. 异步 ZMQ(消息队列)

composer require react/zmq
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; $worker = new Worker('text://0.0.0.0:6161'); $worker->onWorkerStart = function() { global $pull; $loop = Worker::getEventLoop(); $context = new React\ZMQ\Context($loop); $pull = $context->getSocket(ZMQ::SOCKET_PULL); $pull->bind('tcp://127.0.0.1:5555'); $pull->on('error', function ($e) { var_dump($e->getMessage()); }); $pull->on('message', function ($msg) { echo "Received: $msg\n"; }); }; Worker::runAll();

6. 异步 STOMP(消息代理协议)

composer require react/stomp
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; $worker = new Worker('text://0.0.0.0:6161'); $worker->onWorkerStart = function() { global $client; $loop = Worker::getEventLoop(); $factory = new React\Stomp\Factory($loop); $client = $factory->createClient(array('vhost' => '/', 'login' => 'guest', 'passcode' => 'guest')); $client ->connect() ->then(function ($client) use ($loop) { $client->subscribe('/topic/foo', function ($frame) { echo "Message received: {$frame->body}\n"; }); }); }; Worker::runAll();

八、命令行管理:启动、状态、停止与重载

Workerman 官方 README 给出了一套进程管理命令(在start.php场景下):

php start.php start # 前台启动 php start.php start -d # 守护进程方式启动 php start.php status # 查看运行状态 php start.php connections # 查看当前连接数 php start.php stop # 停止 php start.php restart # 重启 php start.php reload # 平滑重载(仅 reloadable 的进程)

命令的第一个参数start/-d/status/connections/stop/restart/reload会被映射为内部信号操作。从 Worker.php 的状态常量可见进程存在STATUS_STARTING / STATUS_RUNNING / STATUS_SHUTDOWN / STATUS_RELOADING四种状态。

CRMEB 中的命令封装

CRMEB 通过 ThinkPHP 6 控制台命令封装了上述能力(见 crmeb/README.md):

# 长连接服务(h5 聊天、后台管理员消息通知、新订单弹窗) php think workerman [status] [--d]

参数说明:

  • status:start(启动)/stop(关闭)/restart(重启)/status/connections;
  • --d:守护进程(后台)方式启动;
  • 第二个参数server(可选):admin/chat/channel,可只启动其中某一个服务。

命令实现位于 crmeb/crmeb/command/Workerman.php:

  • init()把 ThinkPHP 的Input参数回填到全局$argv,从而复用 Workerman 的信号解析逻辑;
  • execute()读取 config/workerman.php 配置,依次创建admin Worker(websocket://0.0.0.0:40001)、chat Worker(websocket://0.0.0.0:40002)、channel 内部通讯服务(127.0.0.1:40003);
  • 各服务进程数由配置中的serverCount决定(当前均为 1);
  • PID 文件写入runtime/workerman.pid;
  • 最后调用Worker::runAll()统一启动。

命令注册在 crmeb/config/console.php:workerman→\crmeb\command\Workerman::class,timer→\crmeb\command\Timer::class。

九、CRMEB 中的落地实现:配置、鉴权与消息分发

1. 配置项速查

config/workerman.php 是三段式结构,与上述三个服务一一对应:

配置段协议监听地址端口进程数用途
channel内部 TCP127.0.0.140003—程序与长连接服务之间的内部通讯总线
adminwebsocket0.0.0.0400011后台新订单/退款通知、管理员消息推送
chatwebsocket0.0.0.0400021客户与客服的实时聊天

2. 鉴权流程:Token → 连接映射

以 admin 服务为例,WorkermanHandle.php 的login方法处理前端 WebSocket 传来的type=login消息:从data中取出管理员 Token,调用AdminAuthServices::parseToken()校验,成功后将adminInfo/adminId挂在TcpConnection对象上,并通过WorkermanService::setUser()建立「管理员 ID → 连接」映射;鉴权失败则直接close连接。chat 服务(ChatService.php)同样维护$user(普通用户)与$kefuUser(在线客服)两张映射表。

3. Channel 消息总线与广播

多进程/多服务之间通过 workerman-channel 组件通信:

  • ChannelService.php 封装了Client::connect($config['ip'], $config['port'])、send($type, $data, $ids)与Client::publish($type, $data);send()中的ids为可选的指定用户 ID 列表,不传则广播给全部在线用户;
  • 业务侧(订单创建、退款等)向 channel 发布crmeb/crmeb_chat主题消息;
  • WorkermanService.php 在onWorkerStart中Client::on('crmeb', ...)订阅,收到后按ids遍历$user表逐连接下发;
  • ChatService.php 同样订阅crmeb_chat,若事件携带fun标记则调用ChatHandle对应方法处理,否则直接推送type + data。

4. 统一响应封装

Response.php 提供链式发送工具:connection($conn)->success($type, $data)发送成功消息、fail()发送失败消息、close()发送后关闭连接,最终统一json_encode后send,保证前后端消息格式一致(形如{"type":"...","data":{...}})。

5. 心跳与掉线回收

onMessage每次都会刷新$connection->lastMessageTime(WorkermanService.php);前端心跳类型为ping时服务端直接回ping + now时间戳。配合前述 Timer 扫描,超过 12 秒无消息即判定超时关闭,避免僵尸连接堆积。

十、性能基准与源码目录速览

官方基准测试(硬件环境与结论)

Workerman 官方 README 附带了在如下环境的 ab 压测记录(结果仅供参考,实际表现取决于服务器硬件与业务复杂度):

  • CPU:Intel(R) Core(TM) i3-3220 @ 3.30GHz(4 处理器)
  • 内存:8G
  • 操作系统:Ubuntu 14.04 LTS
  • 压测工具:ApacheBench(ab)
  • PHP:5.5.9

压测代码是一个 3 进程的纯 TCP 服务,onMessage直接回写一个 5 字节 HTTP 响应:

<?php use Workerman\Worker; $worker = new Worker('tcp://0.0.0.0:1234'); $worker->count=3; $worker->onMessage = function($connection, $data) { $connection->send("HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nServer: workerman\r\nContent-Length: 5\r\n\r\nhello"); }; Worker::runAll();

压测命令与核心结果:

ab -n1000000 -c100 -k http://127.0.0.1:1234/
  • 完成请求:1,000,000;失败请求:0;Keep-Alive 请求:1,000,000;
  • Requests per second:138124.14 [#/sec](平均);
  • 平均单请求耗时 0.724ms,99% 请求在 1ms 内完成;
  • Transfer rate:9846.74 KB/s。

需要强调的是:该数据是 Workerman 3.1.4 在特定单机环境下的官方记录,属 README 自带历史数据,不应作为当前仓库或生产环境的通用结论。

仓库内目录结构速览

Workerman 在crmeb/vendor/workerman/workerman下的模块分布:

  • Worker.php:进程容器、信号处理、runAll()入口(版本 3.5.19);
  • WebServer.php:HTTP 静态服务器(虚拟主机 + MIME 映射);
  • Connection/:TcpConnection、UdpConnection、AsyncTcpConnection、AsyncUdpConnection;
  • Events/:Select、Event、Libevent、Swoole及 React 系列事件循环;
  • Lib/:Timer、Constants;
  • Protocols/:Http、Websocket、Ws、Text、Frame、ProtocolInterface及Http/mime.types;
  • Autoloader.php:内置自动加载器。

CRMEB 侧对 Workerman 的二次封装位于 crmeb/crmeb/services/workerman:WorkermanService(admin 推送)、chat/ChatService(客服聊天)、ChannelService(消息总线)、Response(统一响应)、WorkermanHandle/chat/ChatHandle(消息路由与业务处理)。

十一、许可说明

Workerman 以 MIT 许可证开源(见 MIT-LICENSE.txt),可自由用于商业项目。本文所述示例均可在仓库内对应的源码与配置文件中直接查阅验证,建议结合 config/workerman.php、crmeb/crmeb/command/Workerman.php 与 crmeb/README.md 三个文件对照阅读,即可快速搭建出属于自己的长连接业务。

  • 后端
  • 电商
  • 前端

【免费下载链接】CRMEB

🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议

项目地址:https://gitcode.com/gh_mirrors/cr/CRMEB
点击查看免费下载

相关推荐

上一篇:LeechBlock NG 开源项目教程
下一篇:深度解析DB-GPT Text2SQL自动化微调框架:如何实现82.5%执行准确率的技术突破

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询