use Swoole\Redis\Server;
//use Swoole\Coroutine\Redis;
$http = new swoole_http_server("0.0.0.0", 9501);
global $redis;
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$val = $redis->auth('foobared');
$http->set(array(
'reactor_num' => 2, //reactor thread num
'worker_num' => 4, //worker process num
'backlog' => 128, //listen backlog
'max_request' => 50,
'dispatch_mode' => 1,
//'daemonize' => 1,
));
$http->on('WorkerStart', function ($serv, $worker_id){
global $argv;
// var_dump($redis);
if($worker_id >= $serv->setting['worker_num']) {
swoole_set_process_name("php {$argv[0]} task worker");
} else {
swoole_set_process_name("php {$argv[0]} event worker");
}
});
$http->on("start", function ($server) {
echo "Swoole http server is started at http://127.0.0.1:9501\n";
});
$http->on("request", function ($request, $response) use ($redis){
$response->header("Content-Type", "text/plain");
$response->end(json_encode($request->post)."Hello World\n");
$a=$redis->get('aa');
var_dump($a);
posturl("http://182.61.42.187/aa.php",['a','b',$a]);
});
$http->start();
function posturl($url,$data){
//$data=json_encode($post);
$header=array("Content-Type:application/json;charset='utf-8'");
$curl=curl_init();
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl,CURLOPT_HTTPHEADER,$header);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
echo $output;
return '';
}
ab -n 1000 -c 100 -w http://182.61.42.187:9501/ >>test.txt
数据库连接池(Swoole\Coroutine\Channel和Swoole\Coroutine\MySQL)
最佳的方案是进行断线重连 。它的原理是:
(Swoole\Coroutine\Mysql和PDO等其他客户端同理, 此处简单举例)
mysql_query执行后检测返回值
如果mysql_query返回失败,检测错误码发现为2006/2013(这2个错误表示连接失败),再执行一次mysql_connect
执行mysql_connect后,重新执行mysql_query,这时必然会成功,因为已经重新建立了连接
如果mysql_query返回成功,那么连接是有效的,这是一次正常的调用
class MySQLPool {
const POOL_SIZE = 10;
protected $pool;
protected $logger;
static private $instances;
var $host = '';
var $username = '';
var $password = '';
var $dbname = '';
var $port = 3306;
var $pconnect = FALSE;
var $db_debug = FALSE;
var $char_set = 'utf8';
var $dbcollat = 'utf8_general_ci';
static public function instance($params) {
if (!isset(self::$instances[$params])) {
$params = empty($params) ? 'default' : $params;
global $util_db_config;
if (! isset($util_db_config[$params])) {
throw new RuntimeException("You have specified an invalid database connection group.");
}
$config = $util_db_config[$params];
$pool_size = isset($config['pool_size']) ? intval($config['pool_size']) : MySQLPool::POOL_SIZE;
$pool_size = $pool_size <= 0 ? MySQLPool::POOL_SIZE : $pool_size;
self::$instances[$params] = new MySQLPool($config, $pool_size);
}
return self::$instances[$params];
}
/**
* MySQLPool constructor.
* @param int $size 连接池的尺寸
*/
function __construct($params, $size) {
$this->logger = new Logger(array('file_name' => 'mysql_log'));
foreach ($params as $key => $val) {
$this->$key = $val;
}
$this->ycdb = new ycdb(["unix_socket" => ""]);
$this->pool = new Swoole\Coroutine\Channel($size);
for ($i = 0; $i < $size; $i++) {
$mysql = new Swoole\Coroutine\MySQL();
$ret = $this->connect($mysql);
if ($ret) {
$this->pool->push($mysql);
$this->query("SET NAMES '".$this->char_set."' COLLATE '".$this->dbcollat."'");
} else {
throw new RuntimeException("MySQL connect error host={$this->host}, port={$this->port}, user={$this->username}, database={$this->dbname}, errno=[" . $mysql->errno . "], error=[" . $mysql->error . "]");
}
}
}
function insert($table = '', $data = NULL) {
if (empty($table) || empty($data) || !is_array($data)) {
throw new RuntimeException("insert_table_or_data_must_be_set");
}
$ret = $this->ycdb->insert_sql($table, $data);
if (empty($ret) || $ret == -1) {
throw new RuntimeException("insert_sql error [$table][".json_encode($data)."]");
}
$sql = $ret['query'];
$map = $ret['map'];
$sql = str_replace(array_keys($map), "?", $sql);
$ret = $this->query($sql, array_values($map), $mysql);
if (!empty($ret)) {
return $mysql->insert_id;
} else {
return intval($ret);
}
}
function replace($table = '', $data = NULL) {
if (empty($table) || empty($data) || !is_array($data)) {
throw new RuntimeException("replace_table_or_data_must_be_set");
}
$ret = $this->ycdb->replace_sql($table, $data);
if (empty($ret) || $ret == -1) {
throw new RuntimeException("replace_sql error [$table][".json_encode($data)."]");
}
$sql = $ret['query'];
$map = $ret['map'];
$sql = str_replace(array_keys($map), "?", $sql);
$ret = $this->query($sql, array_values($map));
return $ret;
}
function update($table = '', $where = NULL, $data = NULL) {
if (empty($table) || empty($where) || empty($data) || !is_array($data)) {
throw new RuntimeException("update_table_or_data_must_be_set");
}
$ret = $this->ycdb->update_sql($table, $data, $where);
if (empty($ret) || $ret == -1) {
throw new RuntimeException("update_sql error [$table][".json_encode($data)."][".json_encode($where)."]");
}
$sql = $ret['query'];
$map = $ret['map'];
$sql = str_replace(array_keys($map), "?", $sql);
$ret = $this->query($sql, array_values($map));
return $ret;
}
function delete($table = '', $where = NULL) {
if (empty($table) || empty($where)) {
throw new RuntimeException("delete_table_or_where_must_be_set");
}
$ret = $this->ycdb->delete_sql($table, $where);
if (empty($ret) || $ret == -1) {
throw new RuntimeException("replace_sql error [$table][".json_encode($where)."]");
}
$sql = $ret['query'];
$map = $ret['map'];
$sql = str_replace(array_keys($map), "?", $sql);
$ret = $this->query($sql, array_values($map));
return $ret;
}
function get($table = '', $where = array(), $columns = "*") {
if (empty($table) || empty($columns)) {
throw new RuntimeException("select_table_or_columns_must_be_set");
}
$ret = $this->ycdb->select_sql($table, $columns, $where);
if (empty($ret) || $ret == -1) {
throw new RuntimeException("select_sql error [$table][".json_encode($where)."][".json_encode($columns)."]");
}
$sql = $ret['query'];
$map = $ret['map'];
$sql = str_replace(array_keys($map), "?", $sql);
$ret = $this->query($sql, array_values($map));
return $ret;
}
function get_one($table = '', $where = array(), $columns = "*") {
if (empty($table) || empty($columns)) {
throw new RuntimeException("select_table_or_columns_must_be_set");
}
$where['LIMIT'] = 1;
$ret = $this->get($table, $where, $columns);
if (empty($ret) || !is_array($ret)) {
return array();
}
return $ret[0];
}
private function connect(& $mysql, $reconn = false) {
if ($reconn) {
$mysql->close();
}
$options = array();
$options['host'] = $this->host;
$options['port'] = intval($this->port) == 0 ? 3306 : intval($this->port);
$options['user'] = $this->username;
$options['password'] = $this->password;
$options['database'] = $this->dbname;
$ret = $mysql->connect($options);
return $ret;
}
function real_query(& $mysql, & $sql, & $map) {
if (empty($map)) {
return $mysql->query($sql);
} else {
$stmt = $mysql->prepare($sql);
if ($stmt == false) {
return false;
} else {
return $stmt->execute($map);
}
}
}
function query($sql, $map = null, & $mysql = null) {
if (empty($sql)) {
throw new RuntimeException("input_empty_query_sql");
}
try {
$mysql = $this->pool->pop();
$ret = $this->real_query($mysql, $sql, $map);
if ($ret === false) {
$this->logger->LogError("MySQL QUERY FAIL [".$mysql->errno."][".$mysql->error."], sql=[{$sql}], map=[".json_encode($map)."]");
if ($mysql->errno == 2006 || $mysql->errno == 2013) {
//重连MySQL
$ret = $this->connect($mysql, true);
if ($ret) {
$ret = $this->real_query($mysql, $sql, $map);
} else {
throw new RuntimeException("reconnect fail: [" . $mysql->errno . "][" . $mysql->error . "], host={$this->host}, port={$this->port}, user={$this->username}, database={$this->dbname}");
}
}
}
if ($ret === false) {
throw new RuntimeException($mysql->errno . "|" . $mysql->error);
}
$this->pool->push($mysql);
return $ret;
} catch (Exception $e) {
$this->pool->push($mysql);
$this->logger->LogError("MySQL catch exception [".$e->getMessage()."], sql=[{$sql}], map=".json_encode($map));
throw new RuntimeException("MySQL catch exception [".$e->getMessage()."], sql=[{$sql}], map=".json_encode($map));
}
}
}
swoole_process:进程间通过管道传输数据。(write,read)
swoole内存:lock,buffer,table,atomic,mmap,channel,serialize
执行完即释放
$table=new swoole_table(1024);
$table->column('id',$table::TYPE_INT,4);
$table->column('name',$table::TYPE_STRING,64);
$table->create();
$table->set('key1',['id'=>1,'name'=>'test']);
$table->get('key1');
$http=new swoole_http_server('0.0.0.0',9501);
$http->pool='';
$http->on('WorkerStart',function($http,$worker_id){
$http->pool=new Swoole\Coroutine\Channel(10);
for($i=0;$i<10;++$i){
$mysql=new Swoole\Coroutine\MySQL();
$ret=$mysql->connect([
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'password' => '81334f478ed48187',
'database' => 'laravel',
]);
if($ret){
$http->pool->push($mysql);
}else{
echo "mysql connect error";
}
}
});
$http->on('request',function($rep,$req)use($http){
echo 'aa';
$mysql=$http->pool->pop();
var_dump($mysql);
$http->pool->push($mysql);
});
$http->start();
//开启http server
$http = new swoole_http_server("0.0.0.0", 9501);
$http->set(
[
'enable_static_handler' => true,
'document_root' => "/www/wwwroot/www.test.com/thinkphp5/public/static",
'worker_num' => 5 //设置worker进程数
]
);
$http->on('WorkerStart', function (swoole_server $server, $worker_id){
//定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载基础文件
//这里不直接加载start.php的原因是start.php中的代码会直接执行,也就是application\index\controller\Index.php文件(框架的默认首页)
/*
* Container::get('app', [defined('APP_PATH') ? APP_PATH : ''])
->run()
->send();
*/
require __DIR__ . '/../thinkphp/base.php';
});
$http->on('request', function($request, $response){
//适配
/*
*由于swoole http提供的API和原生php代码是有所不同的,比如原生php中获取get参数为直接从全局数组_GET中获取,而swoole http中是通过$request->get()的方式获取,因此要转换成原生的
* */
$_SERVER = [];
if(isset($request->server)){
foreach($request->header as $k => $v){
$_SERVER[strtoupper($k)] = $v;
}
}
$_GET = [];
if(isset($request->get)){
foreach($request->get as $k => $v){
$_GET[$k] = $v;
}
}
$_POST = [];
if(isset($request->post)){
foreach($request->post as $k => $v){
$_POST[$k] = $v;
}
}
//..其余参数用到的继续往后写
ob_start();
// 执行应用并响应
try {
think\Container::get('app', [APP_PATH])
->run()
->send();
}catch (\Exception $e){
//todo
}
$res = ob_get_contents();
ob_end_clean();
$response->header('Content-Type', 'image/jpeg', false);
$response->end($res);
});
$http->start();