Workerman
Что это такое
Workerman — это асинхронный событийно-ориентированный PHP-фреймворк с высокой производительностью, который позволяет легко создавать быстрые и масштабируемые сетевые приложения. Поддерживает HTTP, WebSocket, SSL и другие пользовательские протоколы. Поддерживает libevent, HHVM, ReactPHP.
Требования
Установка
composer require workerman/workerman
Основное использование
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
// Создаём веб-сокет-сервер
$ws_worker = new Worker("websocket://0.0.0.0:2346");
// 4 процесса
$ws_worker->count = 4;
// Выдаётся при новом соединении
$ws_worker->onConnect = function($connection) {
echo "Новое соединение\n";
};
// Выдаётся при получении данных
$ws_worker->onMessage = function($connection, $data) {
// Отправляем приветствие $data
$connection->send('привет ' . $data);
};
// Выдаётся при закрытии соединения
$ws_worker->onClose = function($connection) {
echo "Соединение закрыто\n";
};
// Запускаем рабочий процесс
Worker::runAll();
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
// #### HTTP-рабочий ####
$http_worker = new Worker("http://0.0.0.0:2345");
// 4 процесса
$http_worker->count = 4;
// Выдаётся при получении данных
$http_worker->onMessage = function($connection, $data) {
// $_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER, $_FILES доступны
var_dump($_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER, $_FILES);
// отправляем данные клиенту
$connection->send("привет мир \n");
};
// запускаем все рабочие процессы
Worker::runAll();
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\WebServer;
use Workerman\Worker;
// Веб-сервер
$web = new WebServer("http://0.0.0.0:80");
// 4 процесса
$web->count = 4;
// Устанавливаем корень доменов
$web->addRoot('www.your_domain.com', '/your/path/Web');
$web->addRoot('www.another_domain.com', '/another/path/Web');
// запускаем все рабочие процессы
Worker::runAll();
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
// #### создаём сокет и слушаем порт 1234 ####
$tcp_worker = new Worker("tcp://0.0.0.0:1234");
// 4 процесса
$tcp_worker->count = 4;
// Выдаётся при новом подключении
$tcp_worker->onConnect = function($connection) {
echo "Новое подключение\n";
};
// Выдаётся при получении данных
$tcp_worker->onMessage = function($connection, $data) {
// отправляем данные клиенту
$connection->send("привет $data \n");
};
// Выдаётся при новом подключении
$tcp_worker->onClose = function($connection) {
echo "Подключение закрыто\n";
};
Worker::runAll();
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
// Контекст SSL.
$context = array(
'ssl' => array(
'local_cert' => '/ваш/путь/сервера.pem',
'local_pk' => '/ваш/путь/сервера.key',
'verify_peer' => false,
)
);
// Создание веб-сокета с контекстом SSL.
$ws_worker = new Worker("websocket://0.0.0.0:2346", $context);
// Включаем SSL. Веб-сокеты + SSL означают защищённые веб-сокеты (wss://). **Подходы для HTTPS и т. д.**
*ws_worker->transport = 'ssl';*
*ws_worker->onMessage = function($connection, $data)*
{
// Отправить приветствие $data
$connection->send('hello ' . $data);
};
Worker::runAll();
**Пользовательский протокол**
Protocols/MyTextProtocol.php
namespace Protocols; /**
Пользовательский протокол
Формат Текст + "\n" */ class MyTextProtocol { public static function input($recv_buffer) { // Найти позицию первого вхождения "\n" $pos = strpos($recv_buffer, "\n"); // Не полный пакет. Возвращаем 0, потому что длину пакета рассчитать невозможно if ($pos === false) { return 0; } // Возвращаем длину пакета return $pos + 1; }
public static function decode($recv_buffer) { return trim($recv_buffer); }
public static function encode($data) { return $data."\n"; } }
require_once DIR . '/vendor/autoload.php'; use Workerman\Worker;
// #### MyTextProtocol worker #### $text_worker = new Worker("MyTextProtocol://0.0.0.0:5678");
$text_worker->onConnect = function($connection) { echo "Новое соединение\n"; };
$text_worker->onMessage = function($connection, $data) { // отправить данные клиенту $connection->send("привет мир \n"); };
$text_worker->onClose = function($connection) { echo "Соединение закрыто\n"; };
// запустить всех рабочих Worker::runAll();
**Таймер**
require_once DIR . '/vendor/autoload.php'; use Workerman\Worker; use Workerman\Lib\Timer;
$task = new Worker(); $task->onWorkerStart = function($task) { // 2,5 секунды $time_interval = 2.5; $timer_id = Timer::add($time_interval, function() { echo "Таймер запущен\n"; } ); };
// Запустить всех рабочих Worker::runAll();
**AsyncTcpConnection (tcp/ws/text/frame и т.д.)**
require_once DIR . '/vendor/autoload.php'; use Workerman\Worker; use Workerman\Connection\AsyncTcpConnection;
$worker = new Worker(); $worker->onWorkerStart = function() { // Протокол Websocket для клиента. $ws_connection = new AsyncTcpConnection("ws://echo.websocket.org:80"); $ws_connection->onConnect = function($connection){ $connection->send('привет'); }; $ws_connection->onMessage = function($connection, $data){ echo "получено: $data\n"; }; $ws_connection->onError = function($connection, $code, $msg){ echo "ошибка: $msg\n"; }; $ws_connection->onClose = function($connection){ echo "соединение закрыто\n"; }; $ws_connection->connect(); }; Worker::runAll();
**Асинхронный MySQL от ReactPHP**
```composer require react/mysql```
```php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:6161');
$worker->onWorkerStart = function() {
global $mysql;
$loop = Worker::getEventLoop();
$mysql = new React\MySQL\Connection($loop, array(
'host' => '127.0.0.1',
'dbname' => 'dbname',
'user' => 'user',
'passwd' => 'passwd',
));
$mysql->on('error', function($e){
echo $e;
});
$mysql->connect(function ($e) {
if($e) {
echo $e;
} else {
echo "успешное подключение\n";
}
});
};
$worker->onMessage = function($connection, $data) {
global $mysql;
$mysql->query('показать базы данных' /*trim($data)*/, function ($command, $mysql) use ($connection) {
if ($command->hasError()) {
$error = $command->getError();
} else {
$results = $command->resultRows;
$fields = $command->resultFields;
$connection->send(json_encode($results));
}
});
};
Worker::runAll();
Асинхронный Redis от ReactPHP
composer require clue/redis-react
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Clue\React\Redis\Factory;
use Clue\React\Redis\Client;
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:6161');
$worker->onWorkerStart = function() {
global $factory;
``` **Код на языке PHP:**
```php
$loop = Worker::getEventLoop();
$factory = new Factory($loop);
};
$worker->onMessage = function($connection, $data) {
global $factory;
$factory->createClient('localhost:6379')->then(function (Client $client) use ($connection) {
$client->set('greeting', 'Hello world');
$client->append('greeting', '!');
$client->get('greeting')->then(function ($greeting) use ($connection){
// Hello world!
echo $greeting . PHP_EOL;
$connection->send($greeting);
});
$client->incr('invocation')->then(function ($n) use ($connection){
echo 'This is invocation #' . $n . PHP_EOL;
$connection->send($n);
});
});
};
Worker::runAll();
Код на языке PHP:
composer require react/dns
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:6161');
$worker->onWorkerStart = function() {
global $dns;
// Get event-loop.
$loop = Worker::getEventLoop();
$factory = new React\Dns\Resolver\Factory();
$dns = $factory->create('8.8.8.8', $loop);
};
$worker->onMessage = function($connection, $host) {
global $dns;
$host = trim($host);
$dns->resolve($host)->then(function($ip) use($host, $connection) {
$connection->send("$host: $ip");
},function($e) use($host, $connection){
$connection->send("$host: {$e->getMessage()}");
});
};
Worker::runAll();
Код на языке PHP:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:6161');
$worker->onMessage = function($connection, $host) {
$loop = Worker::getEventLoop();
$client = new \React\HttpClient\Client($loop);
$request = $client->request('GET', trim($host));
$request->on('error', function(Exception $e) use ($connection) {
$connection->send($e);
});
$request->on('response', function ($response) use ($connection) {
$response->on('data', function ($data) use ($connection) {
$connection->send($data);
});
});
$request->end();
};
Worker::runAll();
Код на языке PHP:
composer require react/zmq
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker('text://0.0.0.0:6161');
$worker->onWorkerStart = function() {
global $pull;
$loop = Worker::getEventLoop();
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555');
$pull->on('error', function ($e) {
var_dump($e->getMessage());
});
$pull->on('message', function ($msg) {
echo "Received: $msg\n";
});
};
Worker::runAll();
Код на языке PHP:
composer require react/stomp
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
$worker = new Worker('text://0.0.0.0:6161');
$worker->onWorkerStart = function() {
global $client;
$loop = Worker::getEventLoop();
$factory = new React\Stomp\Factory($loop);
$client = $factory->createClient(array('vhost' => '/', 'login' => 'guest', 'passcode' => 'guest'));
$client
->connect()
->then(function ($client) use ($loop) {
$client->subscribe('/topic/foo', function ($frame) {
echo "Message received: {$frame->body}\n";
});
});
};
Worker::runAll();
``` **Бенчмарки**
CPU: Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz и 4 процессора всего Memory: 8G OS: Ubuntu 14.04 LTS Software: ab PHP: 5.5.9
**Код**
```php
<?php
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:1234');
$worker->count=3;
$worker->onMessage = function($connection, $data) {
$connection->send("HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nServer: workerman\r\nContent-Length: 5\r\n\r\nhello");
};
Worker::runAll();
Результат
ab -n1000000 -c100 -k http://127.0.0.1:1234/
This is ApacheBench, Version 2.3 <$Revision: 1528965 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100000 requests
Completed 200000 requests
Completed 300000 requests
Completed 400000 requests
Completed 500000 requests
Completed 600000 requests
Completed 700000 requests
Completed 800000 requests
Completed 900000 requests
Completed 1000000 requests
Finished 1000000 requests
Server Software: workerman/3.1.4
Server Hostname: 127.0.0.1
Server Port: 1234
Document Path: /
Document Length: 5 bytes
Concurrency Level: 100
Time taken for tests: 7.240 seconds
Complete requests: 1000000
Failed requests: 0
Keep-Alive requests: 1000000
Total transferred: 73000000 bytes
HTML transferred: 5000000 bytes
Requests per second: 138124.14 [#/sec] (mean)
Time per request: 0.724 [ms] (mean)
Time per request: 0.007 [ms] (mean, across all concurrent requests)
Transfer rate: 9846.74 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 5
Processing: 0 1 0.2 1 9
Waiting: 0 1 0.2 1 9
Total: 0 1 0.2 1 9
Percentage of the requests served within a certain time (ms)
50% 1
66% 1
75% 1
80% 1
90% 1
95% 1
98% 1
99% 1
100% 9 (longest request)
PHPSocket.IO
php-socks5
php-http-proxy
Workerman выпущен под лицензией MIT (https://github.com/walkor/workerman/blob/master/MIT-LICENSE.txt).
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )