# 例子-集群推送
**`(要求Workerman版本>=3.3.0)`**
基于Worker的多进程(分布式集群)推送系统,集群群发、集群广播。
start.php
```php
<?php
use Workerman\Worker;
require_once __DIR__ . '/Workerman/Autoloader.php';
require_once __DIR__ . '/Channel/src/Server.php';
require_once __DIR__ . '/Channel/src/Client.php';
// 初始化一个Channel服务端
$channel_server = new Channel\Server('0.0.0.0', 2206);
// websocket服务端
$worker = new Worker('websocket://0.0.0.0:4236');
$worker->count=2;
$worker->name = 'pusher';
$worker->onWorkerStart = function($worker)
{
// Channel客户端连接到Channel服务端
Channel\Client::connect('127.0.0.1', 2206);
// 以自己的进程id为事件名称
$event_name = $worker->id;
// 订阅worker->id事件并注册事件处理函数
Channel\Client::on($event_name, function($event_data)use($worker){
$to_connection_id = $event_data['to_connection_id'];
$message = $event_data['content'];
if(!isset($worker->connections[$to_connection_id]))
{
echo "connection not exists\n";
return;
}
$to_connection = $worker->connections[$to_connection_id];
$to_connection->send($message);
});
// 订阅广播事件
$event_name = '广播';
// 收到广播事件后向当前进程内所有客户端连接发送广播数据
Channel\Client::on($event_name, function($event_data)use($worker){
$message = $event_data['content'];
foreach($worker->connections as $connection)
{
$connection->send($message);
}
});
};
$worker->onConnect = function($connection)use($worker)
{
$msg = "workerID:{$worker->id} connectionID:{$connection->id} connected\n";
echo $msg;
$connection->send($msg);
};
// 用来处理http请求,向任意客户端推送数据,需要传workerID和connectionID
$http_worker = new Worker('http://0.0.0.0:4237');
$http_worker->name = 'publisher';
$http_worker->onWorkerStart = function()
{
Channel\Client::connect('127.0.0.1', 2206);
};
$http_worker->onMessage = function($connection, $data)
{
$connection->send('ok');
if(empty($_GET['content'])) return;
// 是向某个worker进程中某个连接推送数据
if(isset($_GET['to_worker_id']) && isset($_GET['to_connection_id']))
{
$event_name = $_GET['to_worker_id'];
$to_connection_id = $_GET['to_connection_id'];
$content = $_GET['content'];
Channel\Client::publish($event_name, array(
'to_connection_id' => $to_connection_id,
'content' => $content
));
}
// 是全局广播数据
else
{
$event_name = '广播';
$content = $_GET['content'];
Channel\Client::publish($event_name, array(
'content' => $content
));
}
};
Worker::runAll();
```
## 测试 (假设都是本机127.0.0.1运行)
1、运行服务端
```php
php start.php start
Workerman[start.php] start in DEBUG mode
----------------------- WORKERMAN -----------------------------
Workerman version:3.2.7 PHP version:5.4.37
------------------------ WORKERS -------------------------------
user worker listen processes status
root ChannelServer frame://0.0.0.0:2206 1 [OK]
root pusher websocket://0.0.0.0:4236 2 [OK]
root publisher http://0.0.0.0:4237 1 [OK]
----------------------------------------------------------------
Press Ctrl-C to quit. Start success.
```
2、客户端连接服务端
打开chrome浏览器,按F12打开调试控制台,在Console一栏输入(或者把下面代码放入到html页面用js运行)
```php
// 假设服务端ip为127.0.0.1,测试时请改成实际服务端ip
ws = new WebSocket("ws://127.0.0.1:4236");
ws.onmessage = function(e) {
alert("收到服务端的消息:" + e.data);
};
```
3、通过调用http接口推送
url访问 ```[http://127.0.0.1:4237/?content={$content}```](http://127.0.0.1:4237/?content=%7B%24content%7D%60%60%60) 向所有客户端连接推送```$content```数据
url访问 ```[http://127.0.0.1:4237/?to\_worker\_id={$worker\_id}&to\_connection\_id={$connection\_id}&content={$content}```向某个worker进程中的某个客户端连接推送```$content```数据](http://127.0.0.1:4237/?to_worker_id=%7B%24worker_id%7D&to_connection_id=%7B%24connection_id%7D&content=%7B%24content%7D%60%60%60%E5%90%91%E6%9F%90%E4%B8%AAworker%E8%BF%9B%E7%A8%8B%E4%B8%AD%E7%9A%84%E6%9F%90%E4%B8%AA%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BF%9E%E6%8E%A5%E6%8E%A8%E9%80%81%60%60%60%24content%60%60%60%E6%95%B0%E6%8D%AE)
注意:测试时把```127.0.0.1````{$worker_id}````{$connection\_id}``` 和```{$content}``` 换成实际值
- 序言
- 原理
- 开发必读
- 入门指引
- 特性
- 简单的开发示例
- 安装
- 环境要求
- 下载安装
- 启动停止
- 开发流程
- 开发前必读
- 目录结构
- 开发规范
- 基本流程
- 通讯协议
- 通讯协议作用
- 定制通讯协议
- 一些例子
- Worker类
- 构造函数
- 属性
- id
- count
- name
- protocol
- transport
- reusePort
- connections
- stdoutFile
- pidFile
- logFile
- user
- reloadable
- daemonize
- globalEvent
- 回调属性
- onWorkerStart
- onWorkerReload
- onConnect
- onMessage
- onClose
- onBufferFull
- onBufferDrain
- onError
- 接口
- runAll
- stopAll
- listen
- TcpConnection类
- 属性
- id
- protocol
- worker
- maxSendBufferSize
- defaultMaxSendBufferSize
- maxPackageSize
- 回调属性
- onMessage
- onClose
- onBufferFull
- onBufferDrain
- onError
- 接口
- send
- getRemoteIp
- getRemotePort
- close
- destroy
- pauseRecv
- resumeRecv
- pipe
- AsyncTcpConnection类
- 构造函数
- connect
- reconnect
- transport
- Timer定时器类
- add
- del
- 定时器注意事项
- WebServer
- 调试
- 基本调试
- 查看运行状态
- 网络抓包
- 跟踪系统调用
- 常用组件
- GlobalData数据共享组件
- GlobalDataServer
- GlobalDataClient
- Channel分布式通讯组件
- ChannelServer
- channelClient
- 例子-集群推送
- 例子-分组发送
- FileMonitor文件监控组件
- MySQL组件
- workerman/mysql
- swoole/mysql(异步)
- redis组件
- swoole/redis
- 异步http组件
- swoole/http-client
- 异步消息队列组件
- react/zmq
- react/stomp
- 异步dns组件
- swoole/dns
- 常见问题
- 心跳
- 客户端链接失败原因
- 是否支持多线程
- 与其它框架整合
- 运行多个workerman
- 支持哪些协议
- 如何设置进程数
- 查看客户端连接数
- 对象和资源的持久化
- 例子无法工作
- 启动失败
- 停止失败
- 支持多少并发
- 更改代码不生效
- 向指定客户端发送数据
- 如何主动推送消息
- 在其它项目中推送
- 如何实现异步任务
- status里send_fail的原因
- Windows下开发Linux下部署
- 是否支持socket.io
- 终端关闭导致workerman关闭
- 与nginx apache的关系
- 禁用函数检查
- 平滑重启原理
- 为Flash开843端口
- 如何广播数据
- 如何建立udp服务
- 监听ipv6
- 关闭未认证的链接
- 传输加密-ssl/tsl
- 创建wss服务
- 创建https服务
- workerman作为客户端
- 作为ws/wss客户端
- PHP的几种回调写法
- 附录
- Linux内核调优
- 压力测试
- 安装扩展
- websocket协议
- ws协议
- text协议
- frame协议
- 不支持的函数/特性
- 版权信息