# 例子-集群推送
**`(要求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協議
- 不支持的函數/特性
- 版權信息