沒有聽說過或者沒有用過 workerman 的童鞋建議先去官網(wǎng)看下文檔剥纷。
一、安裝 workerman
在項目根目錄執(zhí)行
composer require workerman/workerman
二伟姐、創(chuàng)建自定義 artisan 命令來啟動 workerman 服務(wù)
由于 laravel 不能直接在根目錄下執(zhí)行 php
命令,所以需要創(chuàng)建 artisan
命令用于后面 workerman 服務(wù)的開啟。
1付魔,生成 WorkermanCommand 文件
php artisan make:command WorkermanCommand
執(zhí)行以上命令行會在 app/Console/Commands/ 目錄下生成 WorkermanCommand.php 文件。
<?php
namespace App\Console\Commands;
use Workerman\Worker;
use Illuminate\Console\Command;
class WorkermanCommand extends Command
{
private $server;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'wk {action}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Start a Workerman server.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
global $argv;
$arg = $this->argument('action');
$argv[1] = $argv[2];
$argv[2] = isset($argv[3]) ? "-{$argv[3]}" : '';
switch ($arg) {
case 'start':
$this->start();
break;
case 'stop':
break;
case 'restart':
break;
case 'reload':
break;
case 'status':
break;
case 'connections':
break;
}
}
private function start()
{
// 創(chuàng)建一個Worker監(jiān)聽20002端口飞蹂,不使用任何應(yīng)用層協(xié)議
$this->server = new Worker("tcp://0.0.0.0:20002");
// 啟動4個進(jìn)程對外提供服務(wù)
$this->server->count = 4;
$handler = \App::make('handlers\WorkermanHandler');
// 連接時回調(diào)
$this->server->onConnect = [$handler, 'onConnect'];
// 收到客戶端信息時回調(diào)
$this->server->onMessage = [$handler, 'onMessage'];
// 進(jìn)程啟動后的回調(diào)
$this->server->onWorkerStart = [$handler, 'onWorkerStart'];
// 斷開時觸發(fā)的回調(diào)
$this->server->onClose = [$handler, 'onClose'];
// 運行worker
Worker::runAll();
}
}
我只實現(xiàn)了 start
命令几苍,其他命令童鞋們自行實現(xiàn)吧。
這里使用了 PHP 類方法的回調(diào)陈哑。(PHP幾種回調(diào)寫法)
這里我們創(chuàng)建了一個自定義命令 wk [action]
妻坝,通過此命令即可開啟 workerman 服務(wù)。
在這個自定義命令還引用了其他的類文件惊窖,如:
$handler = \App::make('handlers\WorkermanHandler');
所以刽宪,需要創(chuàng)建一個 WorkermanHandler.php
的文件來處理對應(yīng)的操作。
2爬坑,創(chuàng)建 WorkermanHandler.php
創(chuàng)建文件 app/handlers/WorkermanHandler.php
<?php
namespace handlers;
use Workerman\Lib\Timer;
// 心跳間隔10秒
define('HEARTBEAT_TIME', 10);
class WorkermanHandler
{
// 處理客戶端連接
public function onConnect($connection)
{
echo "new connection from ip " . $connection->getRemoteIp() . "\n";
}
// 處理客戶端消息
public function onMessage($connection, $data)
{
// 向客戶端發(fā)送hello $data
$connection->send('Hello, your send message is: ' . $data);
}
// 處理客戶端斷開
public function onClose($connection)
{
echo "connection closed from ip {$connection->getRemoteIp()}\n";
}
public function onWorkerStart($worker)
{
Timer::add(1, function () use ($worker) {
$time_now = time();
foreach ($worker->connections as $connection) {
// 有可能該connection還沒收到過消息纠屋,則lastMessageTime設(shè)置為當(dāng)前時間
if (empty($connection->lastMessageTime)) {
$connection->lastMessageTime = $time_now;
continue;
}
// 上次通訊時間間隔大于心跳間隔,則認(rèn)為客戶端已經(jīng)下線盾计,關(guān)閉連接
if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
echo "Client ip {$connection->getRemoteIp()} timeout!!!\n";
$connection->close();
}
}
});
}
}
3售担,修改 composer.json
文件,讓 app/Protocols
文件夾下的類文件自動加載署辉。
"autoload": {
"classmap": [
...
"app/Protocols"
],
...
},
至此族铆。workman的命令定義已經(jīng)完成。
使用:
php artisan wk start
如果看到以下內(nèi)容哭尝,說明 workerman 服務(wù)啟動正常:
Workerman[artisan] start in DEBUG mode
----------------------- WORKERMAN -----------------------------
Workerman version:3.5.4 PHP version:7.1.4
------------------------ WORKERS -------------------------------
user worker listen processes status
root none tcp://0.0.0.0:20002 1 [OK]
----------------------------------------------------------------
Press Ctrl+C to quit. Start success.