php使用swoole實(shí)現(xiàn)TCP服務(wù)
更新時(shí)間:2024年04月03日 08:31:09 作者:huaweichenai
這篇文章主要為大家詳細(xì)介紹了php如何使用swoole實(shí)現(xiàn)TCP服務(wù),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下
這里以在Yii框架下示例
一:swoole配置TCP
'swoole' => [ // 日志文件路徑 'log_file' => '@console/log/swoole.log', // 設(shè)置swoole_server錯(cuò)誤日志打印的等級(jí),范圍是0-5。低于log_level設(shè)置的日志信息不會(huì)拋出 'log_level' => 1, // 進(jìn)程的PID存儲(chǔ)文件 'pid_file' => '@console/log/swoole.server.pid', // HTTP協(xié)議配置 'http' => [ 'host' => '0.0.0.0', 'port' => '8889', // 異步任務(wù)的工作進(jìn)程數(shù)量 'task_worker_num' => 4, ], // TCP協(xié)議配置 'tcp' => [ 'host' => '0.0.0.0', 'port' => '14000', // 異步任務(wù)的工作進(jìn)程數(shù)量 'task_worker_num' => 4, // 啟用TCP-Keepalive死連接檢測(cè) 'open_tcp_keepalive' => 1, // 單位秒,連接在n秒內(nèi)沒(méi)有數(shù)據(jù)請(qǐng)求,將開始對(duì)此連接進(jìn)行探測(cè) 'tcp_keepidle' => 5 * 60, // 探測(cè)的次數(shù),超過(guò)次數(shù)后將close此連接 'tcp_keepcount' => 3, // 探測(cè)的間隔時(shí)間,單位秒 'tcp_keepinterval' => 60, // 心跳檢測(cè),此選項(xiàng)表示每隔多久輪循一次,單位為秒 'heartbeat_check_interval' => 2 * 60, // 心跳檢測(cè),連接最大允許空閑的時(shí)間 'heartbeat_idle_time' => 5 * 60, ] ],
二:swoole實(shí)現(xiàn)TCP服務(wù)基類
<?php /** * @link http://www.u-bo.com * @copyright 南京友博網(wǎng)絡(luò)科技有限公司 * @license http://www.u-bo.com/license/ */ namespace console\swoole; use Yii; use yii\helpers\Console; use yii\helpers\ArrayHelper; /* * Swoole Server基類 * * @author wangjian * @since 0.1 */ abstract class BaseServer { /** * @var Swoole\Server */ public $swoole; /** * @var boolean DEBUG */ public $debug = false; /** * __construct */ public function __construct($httpConfig, $tcpConfig, $config = []) { $httpHost = ArrayHelper::remove($httpConfig, 'host'); $httpPort = ArrayHelper::remove($httpConfig, 'port'); $this->swoole = new \swoole_http_server($httpHost, $httpPort); $this->swoole->set(ArrayHelper::merge($config, $httpConfig)); $this->swoole->on('start', [$this, 'onStart']); $this->swoole->on('request', [$this, 'onRequest']); $this->swoole->on('WorkerStart', [$this, 'onWorkerStart']); $this->swoole->on('WorkerStop', [$this, 'onWorkerStop']); $this->swoole->on('task', [$this, 'onTask']); $this->swoole->on('finish', [$this, 'onTaskFinish']); $this->swoole->on('shutdown', [$this, 'onShutdown']); $tcpHost = ArrayHelper::remove($tcpConfig, 'host'); $tcpPort = ArrayHelper::remove($tcpConfig, 'port'); $tcpServer = $this->swoole->listen($tcpHost, $tcpPort, SWOOLE_SOCK_TCP); $tcpServer->set($tcpConfig); $tcpServer->on('connect', [$this, 'onConnect']); $tcpServer->on('receive', [$this, 'onReceive']); $tcpServer->on('close', [$this, 'onClose']); } /* * 啟動(dòng)server */ public function run() { $this->swoole->start(); } /** * Server啟動(dòng)在主進(jìn)程的主線程時(shí)的回調(diào)事件處理 * * @param swoole_server $server */ public function onStart(\swoole_server $server) { $startedAt = $this->beforeExec(); $this->stdout("**Server Start**\n", Console::FG_GREEN); $this->stdout("master_pid: "); $this->stdout("{$server->master_pid}\n", Console::FG_BLUE); $this->onStartHandle($server); $this->afterExec($startedAt); } /** * 客戶端與服務(wù)器建立連接后的回調(diào)事件處理 * * @param swoole_server $server * @param integer $fd * @param integer $reactorId */ abstract public function onConnect(\swoole_server $server, int $fd, int $reactorId); /** * 當(dāng)服務(wù)器收到來(lái)自客戶端的數(shù)據(jù)時(shí)的回調(diào)事件處理 * * @param swoole_server $server * @param integer $fd * @param integer $reactorId * @param string $data */ abstract public function onReceive(\swoole_server $server, int $fd, int $reactorId, string $data); /** * 當(dāng)服務(wù)器收到來(lái)自客戶端的HTTP請(qǐng)求時(shí)的回調(diào)事件處理 * * @param swoole_http_request $request * @param swoole_http_response $response */ abstract public function onRequest(\swoole_http_request $request, \swoole_http_response $response); /** * Worker進(jìn)程/Task進(jìn)程啟動(dòng)時(shí)發(fā)生 * * @param swoole_server $server * @param integer $worker_id */ abstract public function onWorkerStart(\swoole_server $server, int $worker_id); /** * Worker進(jìn)程/Task進(jìn)程終止時(shí)發(fā)生 * * @param swoole_server $server * @param integer $worker_id */ abstract public function onWorkerStop(\swoole_server $server, int $worker_id); /** * 異步任務(wù)處理 * * @param swoole_server $server * @param integer $taskId * @param integer $srcWorkerId * @param mixed $data */ abstract public function onTask(\swoole_server $server, int $taskId, int $srcWorkerId, mixed $data); /** * 異步任務(wù)處理完成 * * @param swoole_server $server * @param integer $taskId * @param mixed $data */ abstract public function onTaskFinish(\swoole_server $server, int $taskId, mixed $data); /** * 客戶端與服務(wù)器斷開連接后的回調(diào)事件處理 * * @param swoole_server $server * @param integer $fd */ abstract public function onClose(\swoole_server $server, $fd); /** * Server正常結(jié)束時(shí)的回調(diào)事件處理 * * @param swoole_server $server */ public function onShutdown(\swoole_server $server) { $startedAt = $this->beforeExec(); $this->stdout("**Server Stop**\n", Console::FG_GREEN); $this->stdout("master_pid: "); $this->stdout("{$server->master_pid}\n", Console::FG_BLUE); $this->onShutdownHandle($server); $this->afterExec($startedAt); } /** * Server啟動(dòng)在主進(jìn)程的主線程時(shí)的自定義事件處理 * * @param swoole_server $server */ protected function onStartHandle(\swoole_server $server) { } /** * Server正常結(jié)束時(shí)的自定義事件處理 * * @param swoole_server $server */ protected function onShutdownHandle(\swoole_server $server) { } /** * 獲取請(qǐng)求路由 * * @param swoole_http_request $request */ protected function getRoute(\swoole_http_request $request) { return ltrim($request->server['request_uri'], '/'); } /** * 獲取請(qǐng)求的GET參數(shù) * * @param swoole_http_request $request */ protected function getParams(\swoole_http_request $request) { return $request->get; } /** * 解析收到的數(shù)據(jù) * * @param string $data */ protected function decodeData($data) { return json_decode($data, true); } /** * Before Exec */ protected function beforeExec() { $startedAt = microtime(true); $this->stdout(date('Y-m-d H:i:s') . "\n", Console::FG_YELLOW); return $startedAt; } /** * After Exec */ protected function afterExec($startedAt) { $duration = number_format(round(microtime(true) - $startedAt, 3), 3); $this->stdout("{$duration} s\n\n", Console::FG_YELLOW); } /** * Prints a string to STDOUT. */ protected function stdout($string) { if (Console::streamSupportsAnsiColors(\STDOUT)) { $args = func_get_args(); array_shift($args); $string = Console::ansiFormat($string, $args); } return Console::stdout($string); } }
三:swoole操作類(繼承swoole基類)
<?php /** * @link http://www.u-bo.com * @copyright 南京友博網(wǎng)絡(luò)科技有限公司 * @license http://www.u-bo.com/license/ */ namespace console\swoole; use Yii; use yii\db\Query; use yii\helpers\Console; use yii\helpers\VarDumper; use apps\sqjc\models\WaterLevel; use apps\sqjc\models\WaterLevelLog; use common\models\Bayonet; use common\models\Device; use common\models\DeviceCategory; /** * Swoole Server測(cè)試類 * * @author wangjian * @since 1.0 */ class Server extends BaseServer { /** * @inheritdoc */ public function onConnect($server, $fd, $reactorId) { $startedAt = $this->beforeExec(); $this->stdout("**Connection Open**\n", Console::FG_GREEN); $this->stdout("fd: "); $this->stdout("{$fd}\n", Console::FG_BLUE); $this->afterExec($startedAt); } /** * @inheritdoc */ public function onReceive($server, $fd, $reactorId, $data) { $startedAt = $this->beforeExec(); $this->stdout("**Received Message**\n", Console::FG_GREEN); $this->stdout("fd: "); $this->stdout("{$fd}\n", Console::FG_BLUE); $this->stdout("data: ");//接收的數(shù)據(jù) $this->stdout("{$data}\n", Console::FG_BLUE); $result = $server->send($fd, '回復(fù)消息'); $this->afterExec($startedAt); } /** * @inheritdoc */ public function onRequest($request, $response) { $startedAt = $this->beforeExec(); $this->stdout("**HTTP Request**\n", Console::FG_GREEN); $this->stdout("fd: "); $this->stdout("{$request->fd}\n", Console::FG_BLUE); $response->status(200); $response->end('success'); $this->afterExec($startedAt); } /** * @inheritdoc */ public function onClose($server, $fd) { $startedAt = $this->beforeExec(); $this->stdout("**Connection Close**\n", Console::FG_GREEN); $this->stdout("fd: "); $this->stdout("{$fd}\n", Console::FG_BLUE); $this->afterExec($startedAt); } /** * @inheritdoc */ public function onTask($server, $taskId, $srcWorkerId, $data) { $startedAt = $this->beforeExec(); $this->stdout("New AsyncTask: "); $this->stdout("{$taskId}\n", Console::FG_BLUE); $this->stdout("{$data}\n", Console::FG_BLUE); $server->finish($data); $this->afterExec($startedAt); } /** * @inheritdoc */ public function onWorkerStop($server, $worker_id) { // Yii::$app->db->close(); } /** * @inheritdoc */ public function onWorkerStart($server, $worker_id) { // Yii::$app->db->open(); } /** * @inheritdoc */ public function onTaskFinish($server, $taskId, $data) { $startedAt = $this->beforeExec(); $this->stdout("AsyncTask finished: "); $this->stdout("{$taskId}\n", Console::FG_BLUE); $this->afterExec($startedAt); } }
四:操作TCP服務(wù)
<?php /** * @link http://www.u-bo.com * @copyright 南京友博網(wǎng)絡(luò)科技有限公司 * @license http://www.u-bo.com/license/ */ namespace console\controllers; use Yii; use yii\helpers\Console; use yii\helpers\FileHelper; use yii\helpers\ArrayHelper; use console\swoole\Server; /** * WebSocket Server controller. * * @see https://github.com/tystudy/yii2-swoole-websocket/blob/master/README.md * * @author wangjian * @since 1.0 */ class SwooleController extends Controller { /** * @var string 監(jiān)聽I(yíng)P */ public $host; /** * @var string 監(jiān)聽端口 */ public $port; /** * @var boolean 是否以守護(hù)進(jìn)程方式啟動(dòng) */ public $daemon = false; /** * @var boolean 是否啟動(dòng)測(cè)試類 */ public $test = false; /** * @var array Swoole參數(shù)配置項(xiàng) */ private $_params; /** * @var array Swoole參數(shù)配置項(xiàng)(HTTP協(xié)議) */ private $_http_params; /** * @var array Swoole參數(shù)配置項(xiàng)(TCP協(xié)議) */ private $_tcp_params; /** * @inheritdoc */ public function beforeAction($action) { if (parent::beforeAction($action)) { //判斷是否開啟swoole拓展 if (!extension_loaded('swoole')) { return false; } //獲取swoole配置信息 if (!isset(Yii::$app->params['swoole'])) { return false; } $this->_params = Yii::$app->params['swoole']; $this->_http_params = ArrayHelper::remove($this->_params, 'http'); $this->_tcp_params = ArrayHelper::remove($this->_params, 'tcp'); foreach ($this->_params as &$param) { if (strncmp($param, '@', 1) === 0) { $param = Yii::getAlias($param); } } $this->_params = ArrayHelper::merge($this->_params, [ 'daemonize' => $this->daemon ]); return true; } else { return false; } } /** * 啟動(dòng)服務(wù) */ public function actionStart() { if ($this->getPid() !== false) { $this->stdout("WebSocket Server is already started!\n", Console::FG_RED); return self::EXIT_CODE_NORMAL; } $server = new Server($this->_http_params, $this->_tcp_params, $this->_params); $server->run(); } /** * 停止服務(wù) */ public function actionStop() { $pid = $this->getPid(); if ($pid === false) { $this->stdout("Tcp Server is already stoped!\n", Console::FG_RED); return self::EXIT_CODE_NORMAL; } \swoole_process::kill($pid); } /** * 清理日志文件 */ public function actionClearLog() { $logFile = Yii::getAlias($this->_params['log_file']); FileHelper::unlink($logFile); } /** * 獲取進(jìn)程PID * * @return false|integer PID */ private function getPid() { $pidFile = $this->_params['pid_file']; if (!file_exists($pidFile)) { return false; } $pid = file_get_contents($pidFile); if (empty($pid)) { return false; } $pid = intval($pid); if (\swoole_process::kill($pid, 0)) { return $pid; } else { FileHelper::unlink($pidFile); return false; } } /** * @inheritdoc */ public function options($actionID) { return ArrayHelper::merge(parent::options($actionID), [ 'daemon', 'test' ]); } /** * @inheritdoc */ public function optionAliases() { return ArrayHelper::merge(parent::optionAliases(), [ 'd' => 'daemon', 't' => 'test', ]); } }
以上就是php使用swoole實(shí)現(xiàn)TCP服務(wù)的詳細(xì)內(nèi)容,更多關(guān)于php swoole實(shí)現(xiàn)TCP服務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PHP面向?qū)ο蟪绦蛟O(shè)計(jì)繼承用法簡(jiǎn)單示例
這篇文章主要介紹了PHP面向?qū)ο蟪绦蛟O(shè)計(jì)繼承用法,結(jié)合具體實(shí)例形式分析了php面向?qū)ο蟪绦蛟O(shè)計(jì)中繼承的相關(guān)概念、原理、使用技巧與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2018-12-12phpQuery采集網(wǎng)頁(yè)實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了phpQuery采集網(wǎng)頁(yè)實(shí)現(xiàn)代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04PHP __autoload函數(shù)(自動(dòng)載入類文件)的使用方法
在使用PHP的OO模式開發(fā)系統(tǒng)時(shí),通常大家習(xí)慣上將每個(gè)類的實(shí)現(xiàn)都存放在一個(gè)單獨(dú)的文件里,這樣會(huì)很容易實(shí)現(xiàn)對(duì)類進(jìn)行復(fù)用,同時(shí)將來(lái)維護(hù)時(shí)也很便利2012-02-02