Giter Club home page Giter Club logo

think-swoole's Introduction

ThinkPHP Swoole 扩展

交流群:787100169 点击加群

安装

首先按照Swoole官网说明安装swoole扩展,然后使用

composer require topthink/think-swoole

安装swoole扩展。

使用方法

直接在命令行下启动HTTP服务端。

php think swoole

启动完成后,默认会在0.0.0.0:8080启动一个HTTP Server,可以直接访问当前的应用。

swoole的相关参数可以在config/swoole.php里面配置(具体参考配置文件内容)。

如果需要使用守护进程方式运行,建议使用supervisor来管理进程

访问静态文件

4.0开始协程风格服务端默认不支持静态文件访问,建议使用nginx来支持静态文件访问,也可使用路由输出文件内容,下面是示例,可参照修改

  1. 添加静态文件路由:
Route::get('static/:path', function (string $path) {
    $filename = public_path() . $path;
    return new \think\swoole\response\File($filename);
})->pattern(['path' => '.*\.\w+$']);
  1. 访问路由 http://localhost/static/文件路径

队列支持

4.0开始协程风格服务端没有task进程了,使用think-queue代替

使用方法见 think-queue

以下配置代替think-queue里的最后一步:监听任务并执行,无需另外起进程执行队列

return [
    // ...
    'queue'      => [
        'enable'  => true,
        //键名是队列名称
        'workers' => [
            //下面参数是不设置时的默认配置
            'default'            => [
                'delay'      => 0,
                'sleep'      => 3,
                'tries'      => 0,
                'timeout'    => 60,
                'worker_num' => 1,
            ],
            //使用@符号后面可指定队列使用驱动
            'default@connection' => [
                //此处可不设置任何参数,使用上面的默认配置
            ],
        ],
    ],
    // ...
];

支持symfony/var-dumper

由于应用是通过php cli启动的,所以默认symfony/var-dumper会将调试信息打印在控制台, 通过配置中间件来支持将调试信息输出在网页上 如下是直接在配置在全局中间件上,也可以在路由定义的时候配置

// app/middleware.php

<?php
// 全局中间件定义文件
return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
    // \think\middleware\LoadLangPack::class,
    // Session初始化
    //\think\middleware\SessionInit::class,
    \think\swoole\middleware\InteractsWithVarDumper::class,
];

think-swoole's People

Contributors

bzp2010 avatar hainuo avatar hyperlife1119 avatar liu21st avatar nhzex avatar overnaive avatar qq475281441 avatar shuipf avatar simplewindorg avatar stylecibot avatar sy-records avatar xavieryang007 avatar xqueezeme avatar yunwuxin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

think-swoole's Issues

think-swoole重启是否应该适当延时?

现在的代码没有增加延时,重启有很大几率出现端口绑定冲突问题,错误代码如下:
`[root@NAS sms]# php think swoole:server restart
Stopping swoole server...

success
Starting swoole server...
[2018-11-10 12:59:15 @28949.0] WARNING swSocket_bind (ERROR 502): bind(127.0.0.1:65535) failed. Error: Address already in use [98]

[Swoole\Exception]
failed to listen server port[127.0.0.1:65535]. Error: Address already in use[98].

当对重启指令部分适当增加点延时后,重启不会提示端口绑定失败。/**
* 重启server
* @access protected
* @return void
*/
protected function restart()
{
$pid = $this->getMasterPid();

    if ($this->isRunning($pid)) {
        $this->stop();
    }
    sleep(1);
    $this->start();
}`

执行结果如下:
`[root@NAS sms]# php think swoole:server restart
Stopping swoole server...

success
Starting swoole server...
[root@NAS sms]#`

中间件失效的问题

使用的 group路由 添加的中间件
swoole 模式下,我这里测试中间件拦截失效

中间件部分我设置

public function handle($request, \Closure $next)
{
return response()->data('xxx');
}

第一次拦截成功返回xxx
第二次不拦截直接执行后续的方法
第三次拦截成功返回xxx
第四次不拦截直接执行后续的方法

一直这样循环

Undefined property: swoole_http_request::$cookie

Thinkphp: 5.1.32
PHP: 7.2.10-0ubuntu0.18.04.1
Swoole: swoole-1.9.6
Thinkphp-swoole: installed with composer

Errors when run with "php think swoole":
Uncaught think\exception\ErrorException: Undefined property: swoole_http_request::$cookie
Uncaught think\exception\ErrorException: Undefined property: swoole_http_request::$get
Uncaught think\exception\ErrorException: Undefined property: swoole_http_request::$post
Uncaught think\exception\ErrorException: Undefined property: swoole_http_request::$files

Valid code(thinphp-swoole/src/Application.php):
48 $_COOKIE = isset($request->cookie) ? $request->cookie: [];
49 $_GET = isset($request->get) ? $requeset->get: [];
50 $_POST = isset($request->post) ? $requeset->post: [];
51 $_FILES = isset($request->files) ? $requeset->files: [];
52 $header = $request->header ?: [];
53 $server = $request->server ?: [];

关于swoole 下静态变量的分析

静态变量在传统php开发中很好用,但是在swoole等常驻内存模式下很容易造成bug
下面是一些thinkphp中比较重要的静态变量,大部分都有可能在swoole模式下造成bug

\think\Model::$initialized;
//原本作用:确保一个模型类中的init方法在一次请求中只被执行一次
//常驻内存下:一个模型只在第一次请求时执行该方法,后续请求不再执行,极有可能会造成bug
\think\Model::$readMaster;
//原本作用:设置某一个或者全部模型是否从主库读取数据
//常驻内存下:如果在一个请求执行了Model::readMaster()方法,\think\Model::$readMaster不会释放,将会影响到其他请求
think\model\concern\ModelEvent::$event;
//原本作用:给模型设置的事件回调
//常驻内存下:随着运行时间不断增加将不断增加运行内存,一次请求增加的事件将影响到另外一次请求
think\model\concern\ModelEvent::$observe;
//没有影响
think\db\Query::$readMaster;
//原本作用:设置某一个或者全部模型是否从主库读取数据
//常驻内存下:如果在一个请求执行了Query::readMaster()方法,Query::$readMaster不会释放,将会影响到其他请求
think\db\Query::$event;
//常驻内存下:一次请求增加的事件将影响到另外一次请求
think\db\Query::$extend;
//扩展查询方法
//几乎没有影响
think\Request::$ip;
//协程下会用bug 常驻内存非协程下没有影响
think\Template::$_varFunctionList;
//常驻内存模式下增加的变量无法释放,造成内存不断增加,模板变量冲突 可能造成bug
think\cache\Driver::$serialize;
//常住内存模式下 一次请求调用registerSerialize()方法后,会对下一次请求有影响
think\Validate::$typeMsg;
//应该基本没有啥影响
think\db\Connection::$instance;
//建立的连接管理实例
//协程模式,高并发下可能会导致数据库操作bug
think\db\Connection::$event;
//连接事件
//随着运行时间不断增加将不断增加运行内存,事件重复执行,一次请求增加的事件将影响到另外一次请求
think\db\Connection::$info;
//数据表信息
//应该没事影响
think\Db::$executeTimes;
//常驻内存下实际是全局执行时间
think\Db::$queryTimes;
//常驻内存下实际是全局执行次数
think\Db::$connection;
//协程模式,高并发下可能会导致数据库操作bug

既然think-swoole出现在官方文档中了,建议最好对这些整理下,做下说明以免使用者在不注意的情况下造成bug。
下个框架版本能对这些改进,即使在swoole下也能完美运行就完美了

installation of think-swoole error

php version: 7.0.13
swoole version: 1.10.5
installation tips:

Fatal error: Uncaught TypeError: Return value of Endroid\Installer\Installer::activate() must be an instance of Endroid\Installer\void, none returned in /mnt/hgfs/www/saletool/vendor/endroid/installer/src/Installer.php:36
Stack trace:
#0 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(232): Endroid\Installer\Installer->activate(Object(Composer\Composer), Object(Composer\IO\ConsoleIO))
#1 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(205): Composer\Plugin\PluginManager->addPlugin(Object(Endroid\Installer\Installer))
#2 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(257): Composer\Plugin\PluginManager->registerPackage(Object(Composer\Package\CompletePackage))
#3 phar:///usr/local/bin/composer/src/Composer/Plugin/PluginManager.php(76): Composer\Plugin\PluginManager->loadRepository(Object(Composer\Repository\InstalledFilesystemRepository))
#4 phar:///usr/local/bin/composer/src/Composer/Factory.php(377): Composer\Plugin\PluginManager->loadInstalledPlugins()
#5 p in /mnt/hgfs/www/saletool/vendor/endroid/installer/src/Installer.php on line 36

swoole 和swoole:server 有什么区别?

我看源码,如果是swoole 启动就会使用自定义的think\swoole\Application;
此时可以启用Websocket服务也可以启用Http服务. 但是如果是swoole:server启动就不使用think\swoole\Application;
问题
1: 请问这两种启动方式的区别是什么?
2: 为什么swoole:server方式启动 不使用think\swoole\Application,而swoole却使用了;
3. 当使用swoole 方式启动Websocket服务时,返回消息是$resp->send(),Websocket 发送消息不应该是 $server->push($frame->fd,$resp->getData())吗?

在swoole中中间件失效的BUG

swoole版本:4.2.1
失效原因:
第一次访问URL到对应控制器时候,会调用中间件,第二次就不会调用了。

失效过程,还原过如下

在thinkphp5中,要对某个类用中间件拦截
需要继承Controller;

2

中间件,官方在Controller控制器的处理如下:
1

问题原因:

swoole的onRequest里第一次访问url的时候,会去执行一次构造方法,再次访问的时候,就不会去执行构造方法。
因此中间件只会被执行一次,再次访问URL时候构造函数里的操作并不会被执行。

swoole 服务器无法启动

框架核心更新到 5.1.24 , swoole 更新到 2.0.x-dev b618376

php think swoole 启动提示

[think\exception\ThrowableError]
Fatal error: Call to a member function getName() on string

php think swoole:server 没有问题

session组件有BUG

BUG过程还原如下

例如:
我们使用index/user/login 进行用户登录,登录后将用户一些信息存储到session中。此时我们会调用 Session::set() 进行用户的session设置。可以成功。

但是我们打开浏览器,清除cookie如下
1

用户会退出登录,没有错。
但是我们再次去登录用户的时候,用户会登录不上,captcha验证码验证组件也会时效。原因在于,当我们用set去设置的时候,会判断是否有session_id存在,如下:
2

其中getId 如下:
/** * 获取session_id * @access public * @return string */ public function getId() { return ThinkCookie::get($this->sessionName) ?: ''; }
会去获取sessionId开头的 cookie,而此时的cookie已经被我们清空了。根本获取不到了id了

由于成员变量,在swoole里已初始化就加载内存中顶了

所以下面的这一段是不会再去执行了
`
empty($this->init) && $this->boot();

boot里面的
if (false === $this->init) {
$this->start();
}
还有这个
if ($sessionId) {
$this->setSession($sessionId, $name, $value);
}
`
session设置就没有作用了

多个开发想法

我想征求下意见

队列

目前有thinkphp-queue,而且非常好用。

不过swoole实现的队列和TP-queue有一些区别。

1.可以共享task worker来运行,对于一些需要后台执行的任务,如果任务不重,但是数量较多,共享worker可以降低资源的消耗,同时提高资源的利用率

2.可以使用swoole提供的协程,协程更简单。

3.启动多个队列更简单,统一管理

RPC

其实大家更习惯传统的运行方式,swoole workerman的方式需要花费额外的时间去了解多进程,常驻内存等一些知识。个人觉得,大多数业务仍然采用传统方式,当存在耗时业务时,通过一种简单的方式投递到think-swoole的后台运行当中

method not exists:think\Request->withInput

[think\exception\ErrorException] Uncaught think\Exception: method not exists:think\Request->withInput in /home/vagrant/code/knowledge/thinkphp/library/ think/Request.php:335 Stack trace: #0 /home/vagrant/code/knowledge/vendor/topthink/think-swoole/src/Application.php(53): think\Request->__call('withInput ', Array) #1 /home/vagrant/code/knowledge/vendor/topthink/think-swoole/src/Swoole.php(131): think\swoole\Application->swoole(Obj ect(Swoole\Http\Request), Object(Swoole\Http\Response)) #2 {main} thrown

协程中数据库问题

协程模式下,同一个worker下全局变量共享,那么数据库连接也应该是共享的,\think\Db::$connection,但是有多个协程在执行,多个协程在复用这个连接,在实际的业务逻辑中又用到了事务,不会存在冲突吗?

比如这种情况:协程A 开启事务 这个事务比较耗时 这是会执行协程B,协程B进行了一个插入操作,返回协程A ,这时候协程A事务回滚,这样协程B的插入操作就失效了。(协程A B 执行不同的请求)
或者类似于这样的其他冲突情况。

Time定时器存在bug

官方文档里要继承自 think\swoole\template\timer,里面有一个
abstract protected function run();

是一个受保护的方法
但是在timer里面投递的系统定时器的时候,需要一个公开的,因此会报错

请问队列怎么用?

用think-queue跑起来了,不过好像是单进程的。看了这个扩展可以多进程去跑,可是不知道怎么用

swoole request isAjax判断有问题

/**
     * 当前是否Ajax请求
     * @access public
     * @param  bool $ajax  true 获取原始ajax请求
     * @return bool
     */
    public function isAjax($ajax = false)
    {
//  这里的HTTP_X_REQUESTED_WITH不存在!
        $value  = $this->server('HTTP_X_REQUESTED_WITH');
        $result = 'xmlhttprequest' == strtolower($value) ? true : false;

        if (true === $ajax) {
            return $result;
        }

        $result           = $this->param($this->config['var_ajax']) ? true : $result;
        $this->mergeParam = false;
        return $result;
    }

2.0.4 启动异常

执行环境

cygwin64

代码

<?php
namespace app\index\controller;

use think\swoole\Server;

class Swoole extends Server
{
	protected $host = '127.0.0.1';
	protected $port = 9502;
	protected $option = [ 
		'worker_num'	=> 4,
		'daemonize'	=> true,
		'backlog'	=> 128
	];

	public function onReceive($server, $fd, $from_id, $data)
	{
		$server->send($fd, 'Swoole: '.$data);
	}
}

执行

php index.php index/swoole/start

报错

PHP Fatal error:  Swoole\Http\Server::start(): require onRequest callback in /home/tp5/vendor/topthink/think-swoole/src/Server.php on line 112



  [think\exception\ErrorException]
  Swoole\Http\Server::start(): require onRequest callback



启动swoole服务器发生内存泄漏

直接命令行php think swoole,内存直接爆了,虽然程序还能勉强运行。

swoole4.2.13,thinkphp5.1.23,think-swoole扩展是直接composer安装的。

通过docker 部署出现问题

镜像地址: dragonlhp/nginx-php-fpm-swoole:latest
启动命令:
/usr/bin/php /var/www/html/think swoole
报错:
swoole http server process is already running.

Task执行异常

在v2.0.13版本里,在已运行服务的情况下,使用Task跟直接调用容器里的swoole的时候,均发现

  [think\exception\ErrorException]
  Uncaught think\exception\ClassNotFoundException: class not exists: swoole in /home/liang/tp5/thinkphp/library/think/Cont
  ainer.php:442
  Stack trace:
  #0 /home/liang/tp5/thinkphp/library/think/Container.php(284): think\Container->invokeClass('swoole', Array)
  #1 /home/liang/tp5/thinkphp/library/think/Container.php(132): think\Container->make('swoole', Array, false)
  #2 /home/liang/tp5/vendor/topthink/think-swoole/src/Task.php(33): think\Container::get('swoole')
  #3 [internal function]: think\swoole\Task->async(Object(think\swoole\SuperClosure))
  #4 /home/liang/tp5/thinkphp/library/think/Facade.php(123): call_user_func_array(Array, Array)
  #5 /home/liang/tp5/application/server/controller/Socketserver.php(47): think\Facade::__callStatic('async', Array)
  #6 [internal function]: app\server\controller\SocketServer->task(Object(stdClass))
  #7 /home/liang/tp5/application/server/controller/Socketserver.php(27): call_user_func(Array, Object(stdClass))
  #8 {main}
    thrown

事例

Task::async(function($serv, $task_id, $data){
            $i = 0;
            while ($i < 10) {
                $i++;
                echo $i;
                sleep(1);
            }
        });

验证码无法显示

Http\Response->end(string $html); 只支持HTML的输出,验证码输出是图片格式,所以要使用Http\Response->write(string $data);

app_host 设置不生效

swoole 模式下 nginx 做转发 app_host 设置不生效
image
源码Application.php里的这块是不是应该改为获取配置里的值呢

在代码中无法进行302跳转,

PHP Fatal error: Uncaught think\exception\ErrorException: Swoole\Http\Response::write(): data to send is empty.
设置location 会报这个错误

runtime/swoole.log不断频繁写入swoole的TRACE数据

启动后runtime目录下的swoole.log不断追加swoole携程的TRACE信息,日志文件很快被写得很大,请问这样频繁的创建关闭是正常的么?怎么关闭这个日志

`
[2018-12-13 14:39:24 *23190.0] TRACE ~Context(:38): free stack: ptr=0x7f4b413b2010
[2018-12-13 14:39:24 *23190.0] TRACE Context(:16): alloc stack: size=2097152, ptr=0x7f4b413b2010.
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_func(:245): Create coro id: 439132, coro total count: 1, heap size: 3122608
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_close(:385): coro_close coro id 439132
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_close(:420): close coro and 0 remained. usage size: 2860464. malloc size: 4194304
[2018-12-13 14:39:24 *23190.0] TRACE ~Context(:38): free stack: ptr=0x7f4b413b2010
[2018-12-13 14:39:24 *23190.0] TRACE Context(:16): alloc stack: size=2097152, ptr=0x7f4b413b2010.
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_func(:245): Create coro id: 439133, coro total count: 1, heap size: 3122608
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_close(:385): coro_close coro id 439133
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_close(:420): close coro and 0 remained. usage size: 2860464. malloc size: 4194304
[2018-12-13 14:39:24 *23190.0] TRACE ~Context(:38): free stack: ptr=0x7f4b413b2010
[2018-12-13 14:39:24 *23190.0] TRACE Context(:16): alloc stack: size=2097152, ptr=0x7f4b413b2010.
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_func(:245): Create coro id: 439134, coro total count: 1, heap size: 3122608
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_close(:385): coro_close coro id 439134
[2018-12-13 14:39:24 *23190.0] TRACE sw_coro_close(:420): close coro and 0 remained. usage size: 2860464. malloc size: 4194304

`

composer 未加载

使用swoole后,composer相关包为加载,vendor应该是没有引入

think内核swoole分模块配置有BUG

TP版本:5.1.x-dev版本
TP-Swoole:2.0.x-dev版本

配置BUG问题如下:
有两个模块
默认module为:index
API的module为:api

问题经过还原如下
在API中建立config/app.php配置文件
目录如下/application/api/config/app.php

当我们启动swoole的时候,在onWorkerStart里会初始化读取一次配置,如下;
7
然后去init()去读取配置
1
$dir = $this->configPath . $module;
在workerstart的时候已经加载到内存中没有问题。

问题出现:

但是当我们在api模块下,建立一个config/app.php
配置如下:
return [ // 默认输出类型 'default_return_type' => 'json', ];
访问api/index/index的时候,api模块下的配置会被重载到内存中。
此时api模块下输出的为json格式

但是我们此时切换回index/index/index的时候,当我们访问 index/index/index的时候
而此时 $dir会找不到。所以默认采用内存中上次出现的配置
此时index/index/index 本来应该采用默认配置输出html格式的。却输出了json格式。

解决方式:
在index模块下也建立一个配置,默认输出改为html

希望能更新一下 README 中的错误

README 中有错误,例如:
$swoole=Container::get('swoole');//获取swoole实例
会报错。
use think\swoole\template\Task; 文件不存在。
use think\swoole\facade\Task; 文件不存在。
等等。

Session.php中由于会莫名遇到Cookie类已被使用

use think\facade\Cookie;

里边的方法在调用的Cookie的时候提示 已被占用。 具体产生原因比较模糊,有时候重新 php think swoole的时候就产生了这个问题。 改了别名后可正常使用了
use think\facade\Cookie as ThinkCookie; 然后替换掉Cookie类

自定义服务类出现错误:Swoole\Server::on(): unknown event types[Message]

4, 'daemonize' => false, 'task_worker_num' => 4 //'backlog' => 128 ]; public function onMessage($server, $frame) { echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n"; $server->push($frame->fd, "this is server"); } // 设置了onRequest回调,websocket服务器也可以同时作为http服务器 public function onRequest($request, $response) { $response->end("

Hello Swoole. #this is socket server" . "

"); } public function onTask($server, $task_id, $worker_id, $data) { echo 'task start success,taskID is '.$task_id.PHP_EOL; sleep(10); return ['code'=>0, 'message'=>'OK'];// 返回到 onFinish 中 } public function onFinish($server, $task_id, $data) { echo 'taskId is '.$task_id . PHP_EOL; echo 'task coming data is '. json_encode($data); echo 'task finished....'.PHP_EOL; } public function onClose($server, $fd) { echo "client {$fd} closed\n"; } } 所有回调事件都 在自定义服务里面洗的话,就报这个错误,,unknown event types[XXXX]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.