Swoole 协程Http使用

自己对照文档还有其他老哥的博客捣鼓了一些案例(游戏中的消息提示,任务完成等提示需要红点标明)

一、前期准备

使用docker,下载镜像,运行容器

#下载镜像
docker images phpswoole/swoole
#运行容器
docker run -it  -p 9501:9501 -p 9502:9502 -p 9503:9503 -v <本地目录绝对路径>:<docker路径> <docker image> /bin/bash

二、编写代码

Mysql连接池

<?php


require_once "MysqlDB.php";

class MysqlPool
{
    private static $instance;
    private $pool;
    private $config;
    private $pool_get_timeout;

    /**
     * 获取mysql进程池单例
     * @param null $config
     * @return MysqlPool
     */
    public static function getInstance($config = null)
    {
        if (empty(self::$instance)) {
            if (empty($config)) {
                throw new RuntimeException("mysql config is empty");
            }
            self::$instance = new static($config);
        }
        return self::$instance;
    }

    public function __construct($config)
    {
        if (empty($this->pool)) {
            $this->config = $config;
            $this->pool   = new \Swoole\Coroutine\Channel($config['pool_size']);
            for ($i = 0; $i < $config['pool_size']; $i++) {
                \go(function () use ($config) {
                    $mysql = new MysqlDB();
                    $res   = $mysql->connect($config['mysql']);
                    if ($res === false) {
                        throw new RuntimeException("Failed to connect mysql server");
                    } else {
                        $this->pool->push($mysql);
                    }
                });
            }
        }
    }

    public function get()
    {
        if ($this->pool->length() > 0) {
            $mysql = $this->pool->pop($this->config['pool_get_timeout']);
            if (false === $mysql) {
                throw new RuntimeException("Pop mysql timeout");
            }
            return $mysql;
        } else {
            throw new RuntimeException("Pool length <= 0");
        }
    }

    public function recycle(MysqlDB $mysql)
    {
        $this->pool->push($mysql);
    }

    /**
     * 获取连接池长度
     * @return mixed
     */
    public function getPoolSize()
    {
        return $this->pool->length();
    }
}

MysqlDB.sql

<?php


class MysqlDB{
    private $connection;
    public function connect($config)
    {
        $connection = new \Swoole\Coroutine\MySQL();
        $res = $connection->connect($config);
        if ($res === false) {
            throw new RuntimeException($connection->connect_error, $connection->errno);
        } else {
            $this->connection = $connection;
        }
        return $res;
    }
    public function query($sql){
        $result = $this->connection->query($sql);
        return $result;
    }}

协程风格的Http服务

<?php

require_once "MysqlPool.php";
require_once "FacilityService.php";
require_once "TaskServer.php";
require_once "common.php";
\Co\run(function () {
    $server = new \Co\Http\Server("0.0.0.0", 9090, false);
    $pool   = MysqlPool::getInstance([
        'pool_size'        => 5,
        'pool_get_timeout' => 1,
        'timeout'          => 1,
        'charset'          => 'utf8',
        'strict_type'      => false,
        'fetch_mode'       => true,
        'mysql'            => [
            'host'     => '127.0.0.1',
            'port'     => '3306',
            'user'     => 'root',
            'password' => 'root',
            'database' => 'test',
        ]
    ]);

    $server->handle('/', function ($request, $response) use ($pool) {
        $mysql = $pool->get();
        $a     = FacilityService::coopConfig(1, $mysql);
//        $res   = $mysql->query("select * from user limit 1");
//        var_dump($a);
        $pool->recycle($mysql);
        $response->end("<h1>Test</h1>");
    });

    $server->handle('/test', function ($request, $response) use ($pool) {
        $user_id = $request->post['user_id'];
        //集市---买
        $channel_market = new \Swoole\Coroutine\Channel(1);
        go(function () use ($user_id, $pool, $channel_market) {
            $mysql = $pool->get();
            //集市---买
            $buy_data = $mysql->query("select * from `market_system` where user_id={$user_id} and is_view = 0 limit 1");
            $channel_market->push(['buy_page' => empty($buy_data) ? 0 : 1]);
            //归还线程
            $pool->recycle($mysql);
        });
        $buy_page = $channel_market->pop();


        //任务---任务
        $channel = new \Swoole\Coroutine\Channel(1);
        go(function () use ($user_id, $pool, $channel) {
            $mysql     = $pool->get();
            $task_list = $mysql->query("SELECT `ut`.`id`,`ut`.`task_id`,`t`.`type`,`t`.`need_value`,`t`.`name`,`t`.`award_type`,`t`.`award`,`ut`.`status`
                                    FROM `user_tasks` `ut`
                                    LEFT JOIN .tasks `t` ON `ut`.`task_id`=t.id and t.is_shelf = 1
                                    WHERE  `ut`.`status` IN (1,2)
                                    AND `ut`.`user_id` = {$user_id}
                                    ORDER BY `ut`.`id` ASC");
            foreach ($task_list as $v) {
                if ($v['status'] == 2) {
                    $channel->push(['task_page' => 1]);
                    break;
                } elseif ($v['status'] == 1) {//未完成 检查状态
                    $status = TaskServer::checkTaskFinish($this->_userId, $v, $mysql);
                    if ($status) {
                        $mysql->query("Update `user_tasks` set status=2 where id={$v['id']}");
                        if (!$channel->isEmpty()) {
                            $channel->push(['task_page' => 1]);
                        }
                    }
                }
            }
            //归还线程
            $pool->recycle($mysql);
        });
        $task_page = $channel->pop();


        //任务---成就
        $channel_achievement = new \Swoole\Coroutine\Channel(1);
        go(function () use ($pool, $user_id, $channel_achievement) {
            $mysql            = $pool->get();
            $achievement_list = $mysql->query("SELECT * FROM `user_achievement` `u` INNER JOIN .achievement `a` ON `u`.`achievement_id`=a.id and a.is_shelf = 1 WHERE  `u`.`user_id` = {$user_id}  AND `u`.`status` = 2 LIMIT 1");
            $channel_achievement->push(['achievement_page' => empty($achievement_list) ? 0 : 1]);
            //归还线程
            $pool->recycle($mysql);
        });
        $achievement_page = $channel_achievement->pop();


        //图鉴
        $channel_map = new \Swoole\Coroutine\Channel(1);
        go(function () use ($pool, $user_id, $channel_map) {
            $mysql    = $pool->get();
            $map_list = $mysql->query("SELECT * FROM `user_chicken_varieties` WHERE `user_id`={$user_id} AND `is_get` = 1 limit 1");
            $channel_map->push(['map_page' => empty($map_list) ? 0 : 1]);
            //归还线程
            $pool->recycle($mysql);
        });
        $channel_page = $channel_map->pop();


        //设施---鸡窝
        $channel_coop = new \Swoole\Coroutine\Channel(1);
        go(function () use ($pool, $user_id, $channel_coop) {
            $mysql        = $pool->get();
            $user_wallet  = $mysql->query("SELECT * FROM `user_data` WHERE `user_id` = {$user_id} limit 1");
            $chicken_coop = $mysql->query("SELECT * FROM `chicken_coop` WHERE `user_id` = {$user_id}");
            $chicken_coop = reformArr($chicken_coop, 'position');
            for ($x = 1; $x <= 8; $x++) {
                //未建造
                if (!isset($chicken_coop[$x])) {
                    if (count($chicken_coop) + 1 == $x && (count($chicken_coop) == 0 || $chicken_coop[$x - 1]['status'] != 6)) {
                        $coop_config = FacilityService::coopConfig($x, $mysql);
                        if ($user_wallet && $user_wallet[0]['gold'] >= $coop_config['unlock_gold']) {
                            //有可解锁
                            $channel_coop->push(['coop_page' => empty($coop_page) ? 0 : 1]);
                            break;
                        }
                    }
                }
            }
            //归还线程
            $pool->recycle($mysql);
        });
        $channel_coop = $channel_coop->pop();

        $return = [
            'market'   => [
                'buy_page'  => $buy_page['buy_page'] ?? 0,
                'sell_page' => 0,
            ],
            'task'     => [
                'task_page'        => $task_page ?: 0,
                'achievement_page' => $achievement_page['achievement_page'] ?? 0,
            ],
            'facility' => [
                'coop_page'  => $channel_coop['coop_page'] ?? 0,
                'other_page' => 0,
            ],
            'map'      => [
                'map_page' => $channel_page['map_page'] ?? 0,
            ],
        ];
        $response->end(json_encode($return));
    });

    $server->handle('/stop', function ($request, $response) use ($server) {
        $response->end("<h1>Stop</h1>");
        $server->shutdown();
    });

    $server->start();
});

协程风格的Websocket客户端

<?php
use Swoole\Coroutine;
use Swoole\Coroutine\Http\Client;
use function Swoole\Coroutine\run;

run(function () {
    $client = new Client('127.0.0.1', 8081);
    $ret = $client->upgrade('/websocket');

    if ($ret) {
        while(true) {
            fwrite(STDOUT,'请输入用户id:');
            $param = fgets(STDIN);
            $client->push($param);
            var_dump($client->recv());
            Coroutine::sleep(0.1);
        }
    }
});
posted @ 2022-08-23 11:19  bilzzard  阅读(103)  评论(0)    收藏  举报