/** * 当Gateway启动的时候触发的回调函数 * @return void */ public function onWorkerStart() { // 分配一个内部通讯端口 $this->lanPort = $this->startPort - posix_getppid() + posix_getpid(); if ($this->lanPort < 0 || $this->lanPort >= 65535) { $this->lanPort = rand($this->startPort, 65535); } // 如果有设置心跳,则定时执行 if ($this->pingInterval > 0) { Timer::add($this->pingInterval, array($this, 'ping')); } // 初始化gateway内部的监听,用于监听worker的连接已经连接上发来的数据 $this->_innerTcpWorker = new Worker("GatewayProtocol://{$this->lanIp}:{$this->lanPort}"); $this->_innerTcpWorker->listen(); $this->_innerUdpWorker = new Worker("GatewayProtocol://{$this->lanIp}:{$this->lanPort}"); $this->_innerUdpWorker->transport = 'udp'; $this->_innerUdpWorker->listen(); // 重新设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); // 设置内部监听的相关回调 $this->_innerTcpWorker->onMessage = array($this, 'onWorkerMessage'); $this->_innerUdpWorker->onMessage = array($this, 'onWorkerMessage'); $this->_innerTcpWorker->onConnect = array($this, 'onWorkerConnect'); $this->_innerTcpWorker->onClose = array($this, 'onWorkerClose'); // 注册gateway的内部通讯地址,worker去连这个地址,以便gateway与worker之间建立起TCP长连接 if (!$this->registerAddress()) { $this->log('registerAddress fail and exit'); Worker::stopAll(); } if ($this->_onWorkerStart) { call_user_func($this->_onWorkerStart, $this); } }
if (isset($_REQUEST['sendTo']) && !empty($_REQUEST['sendTo'])) { $SendTo = $_REQUEST['sendTo']; } $SendContent = json_encode(array("data" => htmlspecialchars($_REQUEST['sendContent']))); if (!empty($SendTo)) { $senderIO->to($SendTo)->emit('new_msg_receive', $SendContent); } else { $senderIO->emit('new_msg_receive', $SendContent); } // return status return $httpConnection->send(json_encode(array("result" => true))); } return $httpConnection->send(json_encode(array("result" => false))); }; // Start listening $innerHttpWorker->listen(); // Init a timer Timer::add(1, function () { global $uidConnectionMap, $senderIO, $lastOnlineCount, $lastOnlinePageCount; $onlineCountNow = count($uidConnectionMap); $onlinePageCountNow = array_sum($uidConnectionMap); // Send updated data when client counts changes if ($lastOnlineCount != $onlineCountNow || $lastOnlinePageCount != $onlinePageCountNow) { $senderIO->emit("update_online_user_counts", json_encode(array("data" => $onlineCountNow))); $lastOnlineCount = $onlineCountNow; $lastOnlinePageCount = $onlinePageCountNow; } }); }); // Start service Worker::runAll();
* @copyright walkor<*****@*****.**> * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ use Workerman\Worker; use Workerman\WebServer; use Workerman\Protocols\Websocket; // 自动加载类 require_once __DIR__ . '/../../Workerman/Autoloader.php'; $recv_worker = new Worker('Websocket://0.0.0.0:8080'); $recv_worker->onWorkerStart = function ($recv_worker) { $send_worker = new Worker('Websocket://0.0.0.0:8008'); $send_worker->onMessage = function ($connection, $data) { }; $recv_worker->sendWorker = $send_worker; $send_worker->listen(); }; $recv_worker->onMessage = function ($connection, $data) use($recv_worker) { foreach ($recv_worker->sendWorker->connections as $send_connection) { //$send_connection->websocketType = "\x82"; $send_connection->send($data); } }; // WebServer $web = new WebServer("http://0.0.0.0:8088"); // WebServer数量 $web->count = 2; // 设置站点根目录 $web->addRoot('www.your_domain.com', __DIR__ . '/Web'); // 如果不是在根目录启动,则运行runAll方法 if (!defined('GLOBAL_START')) {
/** * Fork one worker process. * @param Worker $worker * @throws Exception */ protected static function forkOneWorker($worker) { $pid = pcntl_fork(); // Get available worker id. $id = self::getId($worker->workerId, 0); // For master process. if ($pid > 0) { self::$_pidMap[$worker->workerId][$pid] = $pid; self::$_idMap[$worker->workerId][$id] = $pid; } elseif (0 === $pid) { if ($worker->reusePort) { $worker->listen(); } if (self::$_status === self::STATUS_STARTING) { self::resetStd(); } self::$_pidMap = array(); self::$_workers = array($worker->workerId => $worker); Timer::delAll(); self::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); $worker->setUserAndGroup(); $worker->id = $id; $worker->run(); exit(250); } else { throw new Exception("forkOneWorker fail"); } }
/** * 创建一个子进程 * @param Worker $worker * @throws Exception */ protected static function forkOneWorker($worker) { $pid = pcntl_fork(); // 获得可用的id $id = self::getId($worker->workerId, 0); // 主进程记录子进程pid if ($pid > 0) { self::$_pidMap[$worker->workerId][$pid] = $pid; self::$_idMap[$worker->workerId][$id] = $pid; } elseif (0 === $pid) { // 如果设置了端口复用,则在子进程执行监听 if ($worker->reusePort) { $worker->listen(); } // 启动过程中尝试重定向标准输出 if (self::$_status === self::STATUS_STARTING) { self::resetStd(); } self::$_pidMap = array(); self::$_workers = array($worker->workerId => $worker); Timer::delAll(); self::setProcessTitle('WorkerMan: worker process ' . $worker->name . ' ' . $worker->getSocketName()); self::setProcessUser($worker->user); $worker->id = $id; $worker->run(); exit(250); } else { throw new Exception("forkOneWorker fail"); } }
* @author walkor<*****@*****.**> * @copyright walkor<*****@*****.**> * @link http://www.workerman.net/ * @license http://www.opensource.org/licenses/mit-license.php MIT License */ use Workerman\Worker; use Workerman\WebServer; // 自动加载类 require_once __DIR__ . '/../../Workerman/Autoloader.php'; $first_frame = ''; $current_frame = ''; $last_byte = ''; $ws_worker = new Worker('Websocket://0.0.0.0:8124'); $ws_worker->onWorkerStart = function ($ws_worker) { $connect_worker = new Worker('Websocket://0.0.0.0:8125'); $connect_worker->listen(); $connect_worker->onMessage = function () { }; $ws_worker->ConnectWorker = $connect_worker; }; $ws_worker->onMessage = function ($connection, $data) use($ws_worker) { foreach ($ws_worker->ConnectWorker->connections as $client_connection) { $client_connection->send($data); } }; // WebServer $web = new WebServer("http://0.0.0.0:8123"); // WebServer数量 $web->count = 2; // 设置站点根目录 $web->addRoot('www.your_domain.com', __DIR__ . '/Web');
/** * 当Gateway启动的时候触发的回调函数 * @return void */ public function onWorkerStart() { // 分配一个内部通讯端口 $this->lanPort = $this->startPort + $this->id; // 如果有设置心跳,则定时执行 if ($this->pingInterval > 0) { $timer_interval = $this->pingNotResponseLimit > 0 ? $this->pingInterval / 2 : $this->pingInterval; Timer::add($timer_interval, array($this, 'ping')); } if (!class_exists('\\Protocols\\GatewayProtocol')) { class_alias('\\GatewayWorker\\Protocols\\GatewayProtocol', 'Protocols\\GatewayProtocol'); } // 初始化gateway内部的监听,用于监听worker的连接已经连接上发来的数据 $this->_innerTcpWorker = new Worker("GatewayProtocol://{$this->lanIp}:{$this->lanPort}"); $this->_innerTcpWorker->listen(); // 重新设置自动加载根目录 Autoloader::setRootPath($this->_appInitPath); // 设置内部监听的相关回调 $this->_innerTcpWorker->onMessage = array($this, 'onWorkerMessage'); $this->_innerTcpWorker->onConnect = array($this, 'onWorkerConnect'); $this->_innerTcpWorker->onClose = array($this, 'onWorkerClose'); // 注册gateway的内部通讯地址,worker去连这个地址,以便gateway与worker之间建立起TCP长连接 $this->registerAddress(); if ($this->_onWorkerStart) { call_user_func($this->_onWorkerStart, $this); } }
global $sender_io; $to = @$_POST['to']; // 有指定uid则向uid所在socket组发送数据 if ($to) { $sender_io->to($to)->emit('new_msg', @$_POST['content']); // 否则向所有uid推送数据 } else { $sender_io->emit('new_msg', @$_POST['content']); } // http接口返回ok return $http_connection->send('ok'); } return $http_connection->send('fail'); }; // 执行监听 $inner_http_worker->listen(); // 一个定时器,定时向所有uid推送当前uid在线数及在线页面数 Timer::add(1, function () { global $uidConnectionMap, $sender_io, $last_online_count, $last_online_page_count; $online_count_now = count($uidConnectionMap); $online_page_count_now = array_sum($uidConnectionMap); // 只有在客户端在线数变化了才广播,减少不必要的客户端通讯 if ($last_online_count != $online_count_now || $last_online_page_count != $online_page_count_now) { $sender_io->emit('update_online_count', "当前<b>{$online_count_now}</b>人在线,共打开<b>{$online_page_count_now}</b>个页面"); $last_online_count = $online_count_now; $last_online_page_count = $online_page_count_now; } }); }); // 启动一个webserver,用于吐html css js,方便展示 // 这个webserver服务不是必须的,可以将这些html css js文件放到你的项目下用nginx或者apache跑
/** * 当Gateway启动的时候触发的回调函数 * @return void */ public function onWorkerStart() { // 分配一个内部通讯端口 $this->lanPort = $this->startPort + $this->id; // 如果有设置心跳,则定时执行 if ($this->pingInterval > 0) { $timer_interval = $this->pingNotResponseLimit > 0 ? $this->pingInterval / 2 : $this->pingInterval; Timer::add($timer_interval, array($this, 'ping')); } // 如果BusinessWorker ip不是127.0.0.1,则需要加gateway到BusinessWorker的心跳 if ($this->lanIp !== '127.0.0.1') { Timer::add(self::PERSISTENCE_CONNECTION_PING_INTERVAL, array($this, 'pingBusinessWorker')); } // 如果Register服务器不在本地服务器,则需要保持心跳 if (strpos($this->registerAddress, '127.0.0.1') !== 0) { Timer::add(self::PERSISTENCE_CONNECTION_PING_INTERVAL, array($this, 'pingRegister')); } if (!class_exists('\\Protocols\\GatewayProtocol')) { class_alias('\\Utils\\GatewayWorker\\Protocols\\GatewayProtocol', 'Protocols\\GatewayProtocol'); } // 初始化gateway内部的监听,用于监听worker的连接已经连接上发来的数据 $this->_innerTcpWorker = new Worker("GatewayProtocol://{$this->lanIp}:{$this->lanPort}"); $this->_innerTcpWorker->listen(); // 重新设置自动加载根目录 Autoloader::setRootPath($this->_autoloadRootPath); // 设置内部监听的相关回调 $this->_innerTcpWorker->onMessage = array($this, 'onWorkerMessage'); $this->_innerTcpWorker->onConnect = array($this, 'onWorkerConnect'); $this->_innerTcpWorker->onClose = array($this, 'onWorkerClose'); // 注册gateway的内部通讯地址,worker去连这个地址,以便gateway与worker之间建立起TCP长连接 $this->registerAddress(); if ($this->_onWorkerStart) { call_user_func($this->_onWorkerStart, $this); } }
// worker进程启动后建立一个内部通讯端口 $worker->onWorkerStart = function ($worker) { // 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符 $inner_text_worker = new Worker('Text://0.0.0.0:5678'); $inner_text_worker->onMessage = function ($connection, $buffer) { $inner_text_worker->count = 3; global $worker; // $data数组格式,里面有uid,表示向那个uid的页面推送数据 $data = json_decode($buffer, true); $uid = $data['uid']; // 通过workerman,向uid的页面推送数据 $ret = sendMessageByUid($uid, $buffer); // 返回推送结果 $connection->send($ret ? 'ok' : 'fail'); }; $inner_text_worker->listen(); }; // 新增加一个属性,用来保存uid到connection的映射 $worker->uidConnections = array(); // 当有客户端发来消息时执行的回调函数 $worker->onMessage = function ($connection, $data) use($worker) { // 判断当前客户端是否已经验证,既是否设置了uid if (!isset($connection->uid)) { // 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证) $connection->uid = $data; /* 保存uid到connection的映射,这样可以方便的通过uid查找connection, * 实现针对特定uid推送数据 */ $worker->uidConnections[$connection->uid] = $connection; return; }