workerman是什么?
Workerman是一个异步事件驱动的PHP框架,具有高性能,可轻松构建快速,可扩展的网络应用程序。支持HTTP,Websocket,SSL和其他自定义协议。支持libevent,HHVM,ReactPHP。
要求
PHP 5.3或更高版本
兼容POSIX的操作系统(Linux,OSX,BSD)
用于PHP的POSIX和PCNTL扩展
安装
composer require workerman/workerman
基本用法
websocket服务器
-
- require_once __DIR__ . '/vendor/autoload.php';
-
- use Workerman\Worker;
-
-
-
- // 创建一个Websocket服务器
-
- $ws_worker = new Worker("websocket://0.0.0.0:2346");
-
-
-
- $ws_worker->count = 4;
-
-
-
- // 在新连接到来时发出
-
- $ws_worker->onConnect = function($connection)
-
- {
-
- echo "New connection\n";
-
- };
-
-
-
- // 接收数据时发出
-
- $ws_worker->onMessage = function($connection, $data)
-
- {
-
- // Send hello $data
-
- $connection->send('hello ' . $data);
-
- };
-
-
-
- // 连接关闭时发出
-
- $ws_worker->onClose = function($connection)
-
- {
-
- echo "Connection closed\n";
-
- };
-
-
-
- // 运行worker
-
- Worker::runAll();
http服务器
- require_once __DIR__ . '/vendor/autoload.php';
-
- use Workerman\Worker;
-
-
-
- // #### http worker ####
-
- $http_worker = new Worker("http://0.0.0.0:2345");
-
-
-
- $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("hello world \n");
-
- };
-
-
-
- // 运行所有workers
-
- Worker::runAll();
WebServer
- require_once __DIR__ . '/vendor/autoload.php';
-
- use Workerman\WebServer;
-
- use Workerman\Worker;
-
-
-
- // WebServer
-
- $web = new WebServer("http://0.0.0.0:80");
-
-
-
- $web->count = 4;
-
-
-
- $web->addRoot('www.your_domain.com', '/your/path/Web');
-
- $web->addRoot('www.another_domain.com', '/another/path/Web');
-
-
-
- Worker::runAll();
TCP服务器
- require_once __DIR__ . '/vendor/autoload.php';
-
- use Workerman\Worker;
-
-
-
- // #### 创建socket并监听1234端口 ####
-
- $tcp_worker = new Worker("tcp://0.0.0.0:1234");
-
-
-
- $tcp_worker->count = 4;
-
-
-
- //在新连接到来时发出
-
- $tcp_worker->onConnect = function($connection)
-
- {
-
- echo "New Connection\n";
-
- };
-
-
-
- // 接收数据时发出
-
- $tcp_worker->onMessage = function($connection, $data)
-
- {
-
- // 发送数据给客户端
-
- $connection->send("hello $data \n");
-
- };
-
-
-
- // 在新连接到来时发出
-
- $tcp_worker->onClose = function($connection)
-
- {
-
- echo "Connection closed\n";
-
- };
-
-
-
- Worker::runAll();
启用SSL
- require_once __DIR__ . '/vendor/autoload.php';
-
- use Workerman\Worker;
-
-
-
- // SSL环境
-
- $context = array(
-
- 'ssl' => array(
-
- 'local_cert' => '/your/path/of/server.pem',
-
- 'local_pk' => '/your/path/of/server.key',
-
- 'verify_peer' => false,
-
- )
-
- );
-
-
-
- // 创建一个带有ssl的Websocket服务器。
-
- $ws_worker = new Worker("websocket://0.0.0.0:2346", $context);
-
-
-
- // 启用SSL。WebSocket+SSL意味着安全的WebSocket (wss://)。
-
- //类似的Https方法等等。
-
- $ws_worker->transport = 'ssl';
-
-
-
- $ws_worker->onMessage = function($connection, $data)
-
- {
-
- // 发送hello $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");
-
- // 不是一个完整的package。返回0,因为package的长度无法计算
-
- if($pos === false)
-
- {
-
- return 0;
-
- }
-
- // 返回package的长度
-
- 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 "New connection\n";
-
- };
-
-
-
- $text_worker->onMessage = function($connection, $data)
-
- {
-
- // 发送数据给客户端
-
- $connection->send("hello world \n");
-
- };
-
-
-
- $text_worker->onClose = function($connection)
-
- {
-
- echo "Connection closed\n";
-
- };
-
-
-
- // 运行所有workers
-
- 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 "Timer run\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('hello');
-
- };
-
- $ws_connection->onMessage = function($connection, $data){
-
- echo "recv: $data\n";
-
- };
-
- $ws_connection->onError = function($connection, $code, $msg){
-
- echo "error: $msg\n";
-
- };
-
- $ws_connection->onClose = function($connection){
-
- echo "connection closed\n";
-
- };
-
- $ws_connection->connect();
-
- };
-
- Worker::runAll();
ReactPHP的异步Mysql
composer require react/mysql
- 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 "connect success\n";
-
- }
-
- });
-
- };
-
- $worker->onMessage = function($connection, $data) {
-
- global $mysql;
-
- $mysql->query('show databases' /*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();
ReactPHP的Async Redis
composer require clue/redis-react
- 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;
-
- $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();
Aysnc dns的ReactPHP
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();
ReactPHP的Http客户端
composer require react/http-client
- 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();
ReactPHP的ZMQ
composer require react/zmq
- 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();
react的STOMP
composer requirereact/stomp
-
- 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();
可用命令
- php start.php start
- php start.php start -d
php start.php status [object Object]
- php start.php connections
-
- php start.php stop
-
- php start.php restart
-
- php start.php reload
基准
- CPU: Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz and 4 processors totally
-
- Memory: 8G
-
- OS: Ubuntu 14.04 LTS
-
- Software: ab
-
- PHP: 5.5.9
代码
-
- 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)
以上就是workerman的基本用法(示例详解)的详细内容