function server_loop() { while (true) { $read_fds = $this->fds; $write = $exp = null; if (stream_select($read_fds, $write, $exp, null)) { foreach ($read_fds as $socket) { $socket_id = (int) $socket; if ($socket_id == $this->server_socket_id) { if ($client_socket_id = parent::accept()) { $this->fds[$client_socket_id] = $this->client_sock[$client_socket_id]; $this->protocol->onConnect($this, $client_socket_id, 0); } } else { $data = Stream::read($socket, $this->buffer_size); if ($data !== false) { $this->protocol->onReceive($this, $socket_id, 0, $data); } else { $this->close($socket_id); } } } } } }
/** * 向任意 worker 进程或者 task 进程发送消息 * * 和 swoole 不同的是, 它支持服务器集群下向任意集群去投递数据 * * @param $data * @param int $workerId * @param int $serverId * @return bool */ public function sendMessage($data, $workerId, $serverId = -1) { if ($serverId === -1) { return $this->server->sendMessage($data, $workerId); } else { $client = Clusters\Client::getClient($serverId, $workerId, true); if (!$client) { return false; } return $client->sendData('msg', $data, 'Task'); } }
public function onReceive($server, $fd, $fromId, $data) { /** * @var \Swoole\Server $server */ $tmp = @msgpack_unpack($data); if ($tmp && is_object($tmp)) { $data = $tmp; unset($tmp); if ($data instanceof \stdClass) { if ($data->bind) { # 绑定进程ID $server->bind($fd, $data->id); return; } if ($key = \MyQEE\Server\Register\Client::$host->key) { # 需要解密 $data = \MyQEE\Server\RPC\Server::decryption($data, $key); # 解密失败 if (!$data) { return; } } $eof = \MyQEE\Server\RPC\Server::$EOF; switch ($data->type) { case 'task': case 'taskWait': $rs = Server::$workerTask->onTask($server, $data->id, $data->wid, $data->data, $data->sid); if ($rs !== null || $data->type === 'taskWait') { # 执行 Finish $rsData = new \stdClass(); $rsData->id = $data->id; $rsData->data = $rs; $rsData->wname = $data->wname; if ($key) { # 加密数据 $rsData = \MyQEE\Server\RPC\Server::encrypt($rsData, $key) . $eof; } else { # 格式化数据 $rsData = msgpack_pack($rsData) . $eof; } $server->send($fd, $rsData, $fromId); } break; } } } else { Server::$instance->warn("task server get error msgpack data length: " . strlen($data)); Server::$instance->debug($data); $this->server->close($fd); } }
public function start($dryRun = false) { $port = $this->choosePort(); $this->sendCommand('status', $port, $error); // @codeCoverageIgnoreStart if (!$error) { $this->cliOutput('error', 'Service already started'); return false; } // @codeCoverageIgnoreEnd $this->prepareServiceAwareComponents(); $this->debug and $this->prepareDebugObservers(); if (!$dryRun) { $this->initSwoole(); $this->swoole->start(); } return true; }
/** * 添加的自定义端口服务 */ protected function initSockets() { foreach (self::$config['sockets'] as $key => $setting) { if (in_array(strtolower($key), ['main', 'task', 'api', 'manager', 'registerserver'])) { self::warn("自定义端口服务关键字不允许是 Main, Task, API, Manager, RegisterServer, 已忽略配置, 请修改配置 sockets.{$key}."); continue; } foreach ((array) $setting['link'] as $st) { $opt = $this->parseSockUri($st); $listen = self::$server->listen($opt->host, $opt->port, $opt->type); if (!isset(self::$workers[$key])) { self::$workers[$key] = $key; } # 设置参数 $listen->set($this->getSockConf($key)); # 设置回调 $this->setListenCallback($key, $listen, $opt); $this->info("add listen: {$st}"); } } }
/** * 向任意 worker 进程或者 task 进程发送消息 * * 和 swoole 不同的是, 它支持服务器集群下向任意集群去投递数据 * * @param $data * @param int $workerId * @param int $serverId * @param string $serverGroup * @return bool */ public function sendMessage($data, $workerId, $serverId = -1, $serverGroup = null) { if ($serverId < 0 || Server::$clustersType === 0 || $this->serverId === $serverId && null === $serverGroup) { # 没有指定服务器ID 或者 本服务器 或 非集群模式 if ($this->name !== 'Main') { $obj = new \stdClass(); $obj->_sys = true; $obj->name = $this->name; $obj->sid = Server::$serverId; $obj->data = $data; $data = $obj; } return $this->server->sendMessage($data, $workerId); } else { $client = Clusters\Client::getClient($serverGroup, $serverId, $workerId, true); if (!$client) { return false; } return $client->sendData('msg', $data, $this->name); } }
/** * 发送响应 * @param $client_id * @param \Swoole\Response $response * @return unknown_type */ function response($client_id, $response) { if (!isset($response->head['Date'])) { $response->head['Date'] = gmdate("D, d M Y H:i:s T"); } if (!isset($response->head['Server'])) { $response->head['Server'] = self::SOFTWARE; } if (!isset($response->head['KeepAlive'])) { $response->head['KeepAlive'] = 'off'; } if (!isset($response->head['Connection'])) { $response->head['Connection'] = 'close'; } if (!isset($response->head['Content-Length'])) { $response->head['Content-Length'] = strlen($response->body); } $out = $response->head(); $out .= $response->body; $this->server->send($client_id, $out); }
function __construct($host, $port, $timeout = 30) { parent::__construct($host, $port, $timeout = 30); }
/** * 收到信息 * * @param \Swoole\Server $server * @param $fd * @param $fromId * @param $data */ public function onReceive($server, $fd, $fromId, $data) { $data = trim($data); if ($data === '') { return; } /** * @var \Swoole\Server $server */ $tmp = @msgpack_unpack($data); if (is_object($tmp) && $tmp instanceof \stdClass) { $rpc = static::$defaultRPC; if ($tmp->rpc) { if (preg_match('#^[\\\\0-9a-z]+$#i', $tmp->rpc)) { $rpc = $tmp->rpc; } } /** * @var RPC $rpc */ $key = $rpc::_getRpcKey(); if ($key) { # 解密数据 $tmp = self::decryption($tmp, $key, $rpc); if (false === $tmp) { # 数据错误 $server->send($fd, '{"type":"close","code":0,"msg":"decryption fail."}' . static::$EOF); $server->close($fd, $fromId); \MyQEE\Server\Server::$instance->debug("register server decryption error, data: " . substr($data, 0, 256) . (strlen($data) > 256 ? '...' : '')); return; } } $data = $tmp; unset($tmp); if ('bind' === $data->type) { if ($this->server->setting['dispatch_mode'] === 5 && is_int($data->id)) { # 支持 worker 绑定 $this->server->bind($fd, $data->id); } return; } $data->rpc = $rpc; if (in_array($this->server->setting['dispatch_mode'], [1, 3]) && ($workerNum = $this->server->setting['worker_num']) > 1) { # 服务器是轮循或抢占模式, 每次请求的可能不是同一个 worker $workerId = $fd % $workerNum; if ($workerId !== $this->server->worker_id) { # 发送给对应的进程去处理 $obj = new \stdClass(); $obj->type = 'call'; $obj->fd = $fd; $obj->fromId = $fromId; $obj->data = $data; $this->sendMessage($data, $workerId); return; } } # 执行RPC调用 $this->call($fd, $fromId, $data); } else { \MyQEE\Server\Server::$instance->warn("rpc get error msgpack data: " . substr($data, 0, 256) . (strlen($data) > 256 ? '...' : '')); $this->server->close($fd, $fromId); return; } }
function daemonize() { $this->server->daemonize(); }
function task($task, $dstWorkerId = -1, $callback = null) { $this->server->task($task, $dstWorkerId = -1, $callback); }
function setProtocol($protocol) { parent::setProtocol($protocol); }
<?php use Swoole\Server; $serv = new Server("127.0.0.1", 9501); $serv->on('receive', function (Server $serv, $fd, $from_id, $data) { echo "[#" . $serv->worker_id . "]\tClient[{$fd}]: {$data}\n"; if ($serv->send($fd, "hello\n") == false) { echo "error\n"; } }); $serv->start();
function task($task, $dstWorkerId = -1) { $this->server->task($task, $dstWorkerId = -1); }