Автор оригинала: David Wong.
Разве PHP не подходит для сервера Интернета вещей?
В традиционном мышлении вам часто говорят, что PHP не подходит для сервера Интернета вещей. Вам нужно изменить Java, node, go и другие языки. Да, это правда, что PHP в традиционном смысле очень сложно быть сервером Интернета вещей, потому что это действительно очень плохо. Конечно, это не значит, что это невозможно сделать полностью. Например, если вы хотите реализовать TCP-сервер, вам может потребоваться написать следующий код:
for ($i = 0;$i <= 1;$i++){
$pid = pcntl_fork();
if($pid){
if($i == 0){
$server = stream_socket_server("tcp://127.0.0.1:9501", $errno, $errstr, STREAM_SERVER_BIND);
}else if($i == 1){
$tickTime = time()+3600;
while (1){
usleep(1);
if($tickTime == time()){
//do my tick func
}
}
}
}
}Смысл приведенного выше кода состоит в том, чтобы создать TCP-сервер в одном процессе и мертвый цикл в другом процессе для определения времени, чтобы реализовать логику таймера. Похоже, что это действительно дерьмово, и это действительно сложно поддерживать для Php, который в целом имеет слабую базу программирования. Конечно, в это время кто-нибудь скажет: разве еще нет рабочего человека? Да, есть рабочие. Worker man-это многопроцессорная платформа PHP, которая плотно инкапсулирует вышеуказанные принципы кода и помогает вам сосредоточиться на реализации логики кода. Так что было бы ошибкой утверждать, что PHP никогда не станет Интернетом вещей. Конечно, в это время некоторые люди могут сказать, что у go language есть программа сотрудничества. Когда вы используете workerman для блокировки вызовов базы данных, эффективность очень низкая, и трудно обеспечить высокий уровень параллелизма. Это верно, но на самом деле мы можем использовать как можно больше процессов, чтобы восполнить этот недостаток, то есть машину кучи. Конечно, если вы действительно хотите поторговаться, это не имеет значения. В это время мы можем уничтожить нашего убийцу, что является процессом сотрудничества swool 4. X.
Swoole в качестве TCP – сервера
Например, следующий код:
$server = new swoole_server("127.0.0.1", 9501);
$server->on('workerstart',function ($ser,$workerId){
if($workerId == 0){
swoole_timer_tick(1000,function (){
});
}
});
$server->on('connect', function ($server, $fd){
echo "connection open: {$fd}\n";
});
$server->on('receive', function ($server, $fd, $reactor_id, $data) {
$server->send($fd, "Swoole: {$data}");
$server->close($fd);
});
$server->on('close', function ($server, $fd) {
echo "connection close: {$fd}\n";
});
$server->start();Мы можем быстро создать многопроцессорный TCP-сервер, и в каждой функции обратного вызова мы можем автоматически создавать среду сотрудничества. В обратном вызове сотрудничества мы можем вызвать API базы данных сотрудничества, чтобы избежать проблемы невозможности обработки других клиентских запросов из-за блокировки вызовов базы данных. Однако многие люди, возможно, не задумывались о том, как изящно создавать свои собственные серверы Интернета вещей. Например, в наших общих службах управления интернет-устройствами могут отображаться следующие коды:
swoole_timer_tick(5000,function (){
$deviceList = $db->getAll();
foreach ($deviceList as $device){
//do your check
/*
*For example, if the device status is 1, process 1 is needed.
*For example, if the equipment status is in 2, process 2 is needed.
*For example, if the equipment status is in 3, process 3 is needed.
*/
}
});Проверка состояния устройства по времени и трансляция На первый взгляд это может показаться безобидным, но когда имеется несколько устройств и логика каждого устройства противоречива, в таком режиме записи легко написать большой объем кода. Более того, в контексте совместной работы, если вы не обращаете внимания на разделение между безопасностью доступа к переменным и контекстом совместной работы, легко могут возникнуть ошибки, что затрудняет обслуживание.
Модель Актера
Что такое актер? Проще говоря, актер-это очень абстрактная параллельная модель. Пространство памяти каждого экземпляра субъекта изолировано друг от друга, что используется для снижения сложности программирования и обслуживания пользователей. Что касается того, как swoole4. X реализует версию субъекта совместной работы, мы объяснили принцип реализации совместной работы со swoole в статье https://segmentfault.com/a/11.
Практика библиотеки моделей актеров
Мы по-прежнему используем библиотеку easyswool/actor для объяснения. Например, если у нас есть тип устройства, мы можем определить субъекта устройства и записать всю логику устройства в модель субъекта. Пример кода выглядит следующим образом:
namespace App\Device;
use EasySwoole\Actor\AbstractActor;
use EasySwoole\Actor\ActorConfig;
use EasySwoole\EasySwoole\Logger;
use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\EasySwoole\Trigger;
class DeviceActor extends AbstractActor
{
private $fd;
private $deviceId;
private $lastHeartBeat;
public static function configure(ActorConfig $actorConfig)
{
$actorConfig->setActorName('Device');
}
protected function onStart()
{
$this->lastHeartBeat = time();
/*
*This parameter is passed at the time of creation
*/
$this->fd = $this->getArg()['fd'];
$this->deviceId = $this->getArg()['deviceId'];
//Record to table manager
DeviceManager::addDevice(new DeviceBean([
'deviceId'=>$this->deviceId,
'actorId'=>$this->actorId(),
'fd'=>$this->fd
]));
//Push message
ServerManager::getInstance()->getSwooleServer()->push($this->fd,"connect to server success,your actorId is {$this->actorId()}");
//Create a timer. If a device does not receive a message in 20s, it will automatically logoff.
$this->tick(20*2000,function (){
if(time() - $this->lastHeartBeat > 20){
$this->exit(-1);
}
});
}
protected function onMessage($msg)
{
if($msg instanceof Command){
switch ($msg->getCommand()){
case $msg::RECONNECT:{
DeviceManager::updateDeviceInfo($this->deviceId,[
'fd'=>$msg->getArg()
]);
$this->fd = $msg->getArg();
Logger::getInstance()->console("deviceId {$this->deviceId} at actorId {$this->actorId()} reconnect success");
ServerManager::getInstance()->getSwooleServer()->push($this->fd,"deviceId {$this->deviceId} at actorId {$this->actorId()} reconnect success");
break;
}
case $msg::WS_MSG:{
$recv = $msg->getArg();
Logger::getInstance()->console("deviceId {$this->deviceId} at actorId {$this->actorId()} recv ws msg: {$recv}");
ServerManager::getInstance()->getSwooleServer()->push($this->fd,'actor recv msg for hash '.md5($recv));
break;
}
case $msg::REPLY_MSG:{
$recv = $msg->getArg();
Logger::getInstance()->console("deviceId {$this->deviceId} at actorId {$this->actorId()} recv reply msg: {$recv}");
ServerManager::getInstance()->getSwooleServer()->push($this->fd,'actor recv reply msg '.$recv);
//Here return a data, which will be returned to the client
return "actorId {$this->actorId()} recv {$recv}";
break;
}
}
}
}
protected function onExit($arg)
{
if($arg == -1){
if(ServerManager::getInstance()->getSwooleServer()->exist($this->fd)){
ServerManager::getInstance()->getSwooleServer()->push($this->fd,"heartbeat lost,actor exit");
ServerManager::getInstance()->getSwooleServer()->close($this->fd);
}
}
DeviceManager::deleteDevice($this->deviceId);
Logger::getInstance()->console("deviceId {$this->deviceId} at actorId {$this->actorId()} exit");
}
protected function onException(\Throwable $throwable)
{
Trigger::getInstance()->throwable($throwable);
}
}В этом акторе мы определяем поведение жизненного цикла этого устройства.
- Устройство подключается к сети, записывает идентификатор устройства и информацию о FD и создает проверка цикла сердцебиения
- После получения сообщения вы можете отправить данные субъекту и обработать соответствующее поведение сообщения.
- Когда устройство находится в автономном режиме, оно может автоматически очищать таймер и другую логику уведомлений и очистки.
Мы ясно видим, что в рамках модели актора нам разрешено управлять моделью устройства с высокой степенью автономии. Конечно, в этой главе основное внимание уделяется тому, как использовать весь процесс для реализации модели актора, чтобы лучше разрабатывать наше оборудование и управлять им. Поэтому я не буду публиковать слишком много кода. Студенты, которые заинтересованы в этом, могут просмотреть полный пример кода https://github.com/easy-swool в демо-версии фреймворка easyswool…
Домашняя страница проекта Easyswool: http://easyswoole.com/Главный склад Easyswool на GitHub https://github.com/easy-tool…, если вы считаете, что наши усилия помогли вам, пожалуйста, дайте звезду.
Оригинал: “https://developpaper.com/actor-concurrency-model-of-php-internet-of-things-development-tool/”