public function startAction() { $worker = new Worker('tcp://0.0.0.0:1234'); $worker->count = 2; $worker->onMessage = array($this, 'onMessage'); $worker->onConnect = array($this, 'onConnect'); $worker->onWorkerStart = array($this, 'onWorkerStart'); $worker->runAll(); }
/** * 当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); } }
public function __construct($socket_name) { parent::__construct($socket_name); $this->onWorkerStart = array($this, 'onStart'); $this->onMessage = array($this, 'onMessage'); $this->onWorkerStop = array($this, 'onStop'); }
/** * Run webserver instance. * * @see Workerman.Worker::run() */ public function run() { $this->_onWorkerStart = $this->onWorkerStart; $this->onWorkerStart = array($this, 'onWorkerStart'); $this->onMessage = array($this, 'onMessage'); parent::run(); }
/** * Execute the console command. * * @return mixed */ public function fire() { // global $argv; $argv[0] = 'artisan'; $argv[1] = 'reload'; Worker::runAll(); }
public static function runAll($AppName = null) { self::$AppName = $AppName ?: "workerman"; static::$logFile = self::workermanTempFile(self::FILE_TYPE_LOG); static::$pidFile = self::workermanTempFile(self::FILE_TYPE_PID); static::$stdoutFile = self::workermanTempFile(self::FILE_TYPE_STDOUT); parent::runAll(); }
/** * 修改原构造方法 * * @param array $config */ public function __construct($config) { parent::__construct(Arr::get($config, 'socketName'), Arr::get($config, 'contextOptions')); // 设置数据 foreach ($config as $k => $v) { if (isset($this->{$k})) { $this->{$k} = $v; } } }
/** * Execute the console command. * * @return mixed */ public function fire() { // $deamonMode = $this->option('deamon'); global $argv; $argv[0] = 'artisan'; $argv[1] = 'restart'; $argv[2] = $deamonMode ? '-d' : null; Worker::runAll(); }
/** * Execute the console command. * * @return mixed */ public function handle() { $ws_worker = new Worker("websocket://0.0.0.0:2346"); $ws_worker->onConnect = function ($connection) { echo "New connection\n"; }; $ws_worker->onMessage = function (TcpConnection $connection, $data) { // 转发数据给所有客户端 foreach ($connection->worker->connections as $connection) { /** @var TcpConnection $connection */ $connection->send($data); } }; $ws_worker->onClose = function ($connection) { echo "Connection closed\n"; }; // Hack Run worker global $argv; $argv = [null, 'start']; $ws_worker->runAll(); }
public function run() { $this->onConnect = array($this, 'onConnect'); // onMessage禁止用户设置回调 $this->onMessage = array($this, 'onMessage'); // 保存用户的回调,当对应的事件发生时触发 $this->onClose = array($this, 'onClose'); // 记录进程启动的时间 $this->_startTime = time(); // 运行父方法 parent::run(); }
/** * 运行 * @see Workerman.Worker::run() */ public function run() { echo 123; $htmlStr = file_get_contents('http://www.baidu.com'); for ($i = 0; $i < 200; $i++) { if ($this->count < 200) { file_put_contents('/www/html/workerman/html/chat1/test.log', $this->count++ . "\r\n", FILE_APPEND); sleep(3); } } echo 456; parent::run(); }
/** * 运行 * @return void */ public function run() { // 设置onMessage连接回调 $this->onConnect = array($this, 'onConnect'); // 设置onMessage回调 $this->onMessage = array($this, 'onMessage'); // 设置onClose回调 $this->onClose = array($this, 'onClose'); // 记录进程启动的时间 $this->_startTime = time(); // 运行父方法 parent::run(); }
/** * 启动服务器 * @return void */ public function start() { if ($this->isStart) { return; } $this->isStart = true; Worker::runAll(); }
* For full copyright and license information, please see the MIT-LICENSE.txt * Redistributions of files must retain the above copyright notice. * * @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; 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;
// On disconnect $socket->on('disconnect', function () use($socket) { if (!isset($socket->uid)) { return; } global $uidConnectionMap, $senderIO; // No users online if (--$uidConnectionMap[$socket->uid] <= 0) { unset($uidConnectionMap[$socket->uid]); } }); }); // New http service to send data to user $senderIO->on('workerStart', function () { // Listening to a port $innerHttpWorker = new Worker('http://0.0.0.0:' . SERVER_API_PORT); // On msg receiving $innerHttpWorker->onMessage = function ($httpConnection, $data) { if (!isset($_REQUEST) && count($_REQUEST) <= 0) { return $httpConnection->send(json_encode(array("result" => false))); } // Send msg url like: "type=sendTextMsg&sendTo=xxxx&sendContent=xxxx" switch ($_REQUEST['type']) { case 'sendTextMsg': global $senderIO; 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);
/** * construt * @param string $socket_name */ public function __construct($socket_name) { parent::__construct($socket_name); $this->onMessage = array($this, 'onMessage'); }
/** * 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"); } }
/** * Destroy connection. * * @return void */ public function destroy() { // Avoid repeated calls. if ($this->_status === self::STATUS_CLOSED) { return; } // Remove event listener. Worker::$globalEvent->del($this->_socket, EventInterface::EV_READ); Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE); // Close socket. @fclose($this->_socket); // Remove from worker->connections. if ($this->worker) { unset($this->worker->connections[$this->_id]); } $this->_status = self::STATUS_CLOSED; // Try to emit onClose callback. if ($this->onClose) { try { call_user_func($this->onClose, $this); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } } // Try to emit protocol::onClose if (method_exists($this->protocol, 'onClose')) { try { call_user_func(array($this->protocol, 'onClose'), $this); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } } if ($this->_status === self::STATUS_CLOSED) { // Cleaning up the callback to avoid memory leaks. $this->onMessage = $this->onClose = $this->onError = $this->onBufferFull = $this->onBufferDrain = null; } }
/** * 创建一个子进程 * @param Worker $worker * @throws Exception */ protected static function forkOneWorker($worker) { $pid = pcntl_fork(); // 主进程记录子进程pid if ($pid > 0) { self::$_pidMap[$worker->workerId][$pid] = $pid; } elseif (0 === $pid) { // 启动过程中尝试重定向标准输出 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->run(); exit(250); } else { throw new Exception("forkOneWorker fail"); } }
/** * Websocket handshake. * * @param string $buffer * @param \Workerman\Connection\TcpConnection $connection * @return int */ protected static function dealHandshake($buffer, $connection) { // HTTP protocol. if (0 === strpos($buffer, 'GET')) { // Find \r\n\r\n. $heder_end_pos = strpos($buffer, "\r\n\r\n"); if (!$heder_end_pos) { return 0; } $header_length = $heder_end_pos + 4; // Get Sec-WebSocket-Key. $Sec_WebSocket_Key = ''; if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Sec-WebSocket-Key not found.<br>This is a WebSocket service and can not be accessed via HTTP.", true); $connection->close(); return 0; } // Calculation websocket key. $new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n"; $handshake_message .= "Upgrade: websocket\r\n"; $handshake_message .= "Sec-WebSocket-Version: 13\r\n"; $handshake_message .= "Connection: Upgrade\r\n"; $handshake_message .= "Server: workerman/" . Worker::VERSION . "\r\n"; $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; // Mark handshake complete.. $connection->websocketHandshake = true; // Websocket data buffer. $connection->websocketDataBuffer = ''; // Current websocket frame length. $connection->websocketCurrentFrameLength = 0; // Current websocket frame data. $connection->websocketCurrentFrameBuffer = ''; // Consume handshake data. $connection->consumeRecvBuffer($header_length); // Send handshake response. $connection->send($handshake_message, true); // There are data waiting to be sent. if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } // blob or arraybuffer if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { self::parseHttpHeader($buffer); try { call_user_func($connection->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } if (!empty($_SESSION) && class_exists('\\GatewayWorker\\Lib\\Context')) { $connection->session = \GatewayWorker\Lib\Context::sessionEncode($_SESSION); } $_GET = $_SERVER = $_SESSION = $_COOKIE = array(); } if (strlen($buffer) > $header_length) { return self::input(substr($buffer, $header_length), $connection); } return 0; } elseif (0 === strpos($buffer, '<polic')) { $policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . ""; $connection->send($policy_xml, true); $connection->consumeRecvBuffer(strlen($buffer)); return 0; } // Bad websocket handshake request. $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Invalid handshake data for websocket. ", true); $connection->close(); return 0; }
/** * Check connection is successfully established or faild. * * @param resource $socket * @return void */ public function checkConnection($socket) { // Check socket state. if ($address = stream_socket_get_name($socket, true)) { // Remove write listener. Worker::$globalEvent->del($socket, EventInterface::EV_WRITE); // Nonblocking. stream_set_blocking($socket, 0); stream_set_read_buffer($socket, 0); // Try to open keepalive for tcp and disable Nagle algorithm. if (function_exists('socket_import_stream') && $this->transport === 'tcp') { $raw_socket = socket_import_stream($socket); socket_set_option($raw_socket, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_option($raw_socket, SOL_TCP, TCP_NODELAY, 1); } // Register a listener waiting read event. Worker::$globalEvent->add($socket, EventInterface::EV_READ, array($this, 'baseRead')); // There are some data waiting to send. if ($this->_sendBuffer) { Worker::$globalEvent->add($socket, EventInterface::EV_WRITE, array($this, 'baseWrite')); } $this->_status = self::STATUS_ESTABLISH; $this->_remoteAddress = $address; // Try to emit onConnect callback. if ($this->onConnect) { try { call_user_func($this->onConnect, $this); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } } // Try to emit protocol::onConnect if (method_exists($this->protocol, 'onConnect')) { try { call_user_func(array($this->protocol, 'onConnect'), $this); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } } } else { // Connection failed. $this->emitError(WORKERMAN_CONNECT_FAIL, 'connect ' . $this->_remoteAddress . ' fail after ' . round(microtime(true) - $this->_connectStartTime, 4) . ' seconds'); if ($this->_status === self::STATUS_CLOSING) { $this->destroy(); } if ($this->_status === self::STATUS_CLOSED) { $this->onConnect = null; } } }
/** * Timer callback. * * @param mixed $_null1 * @param int $_null2 * @param mixed $timer_id */ protected function timerCallback($_null1, $_null2, $timer_id) { if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) { event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]); } try { call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); } catch (\Exception $e) { Worker::log($e); exit(250); } catch (\Error $e) { Worker::log($e); exit(250); } if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) { $this->del($timer_id, self::EV_TIMER_ONCE); } }
/** * 当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); } }
/** * 业务超时回调 * @param int $signal * @throws Exception */ public function timeoutHandler($signal) { switch ($signal) { // 超时时钟 case SIGALRM: // 超时异常 $e = new \Exception("process_timeout", 506); $trace_str = $e->getTraceAsString(); // 去掉第一行timeoutHandler的调用栈 $trace_str = $e->getMessage() . ":\n" . substr($trace_str, strpos($trace_str, "\n") + 1) . "\n"; // 开发者没有设置超时处理函数,或者超时处理函数返回空则执行退出 if (!$this->processTimeoutHandler || !call_user_func($this->processTimeoutHandler, $trace_str, $e)) { Worker::stopAll(); } break; } }
/** * 创建一个子进程 * @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()); $worker->setProcessUserAndRoot(); $worker->id = $id; $worker->run(); exit(250); } else { throw new Exception("forkOneWorker fail"); } }
/** * start server * */ public function start() { Worker::runAll(); }
* * @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; // 设置站点根目录
$gateway->count = 4; // 分布式部署时请设置成内网ip(非127.0.0.1) $gateway->lanIp = '127.0.0.1'; // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000 // 则一般会使用4001 4002 4003 4004 4个端口作为内部通讯端口 $gateway->startPort = 3000; // 心跳间隔 $gateway->pingInterval = 10; // 心跳数据 $gateway->pingData = '{"type":"ping"}'; /* 上线时 为了安全 开启 // 当客户端连接上来时,设置连接的onWebSocketConnect,即在websocket握手时的回调 $gateway->onConnect = function($connection) { $connection->onWebSocketConnect = function($connection , $http_header) { // 可以在这里判断连接来源是否合法,不合法就关掉连接 // $_SERVER['HTTP_ORIGIN']标识来自哪个站点的页面发起的websocket链接 if($_SERVER['HTTP_ORIGIN'] != 'http://chat.zhbor.com') { $connection->close(); } // onWebSocketConnect 里面$_GET $_SERVER是可用的 // var_dump($_GET, $_SERVER); }; }; */ // 如果不是在根目录启动,则运行runAll方法 if (!defined('GLOBAL_START')) { Worker::runAll(); }
/** * construct */ public function __construct($socket_name) { parent::__construct($socket_name); $this->onWorkerStart = array($this, 'onStart'); $this->onConnect = array($this, 'onConnect'); }
/** * Execute the console command. * * @return mixed */ public function fire() { // $deamonMode = $this->option('deamon'); // 检查扩展 if (!extension_loaded('pcntl')) { $this->error("Please install pcntl extension. See http://doc3.workerman.net/install/install.html\n"); return; } if (!extension_loaded('posix')) { $this->error("Please install posix extension. See http://doc3.workerman.net/install/install.html\n"); return; } // 标记是全局启动 define('GLOBAL_START', 1); $applications = Config::get('workerboy.applications'); // 加载所有Applications/*/start.php,以便启动所有服务 foreach ($applications as $application => $config) { $startPath = base_path($application); if (is_file($startPath)) { require_once $startPath; } } // 运行所有服务 global $argv; $argv[0] = 'artisan'; $argv[1] = 'start'; $argv[2] = $deamonMode ? '-d' : null; Worker::runAll(); }