Swoole v4.6.0 版本发布,支持原生 curl 协程客户端
码农天地 -Swoole v4.6.0
版本发布了,同样也是 2021 年的首个版本更新。
作为一个 y 版本发布,此次更新也包含了不兼容的修改以及许多的新功能,下面就来看一看都有哪些改动?
向下不兼容改动从v4.6.0
版本开始将不再支持 PHP7.1
PHP 官方对于 PHP7.1
的支持也早已在 2019 年底结束。
Event::rshutdown()
标记为已弃用,请改用 Coroutine\run
在之前的版本中,如果在index.php
中直接使用go
创建协程
go(function () {
var_dump(Co\System::gethostbyname('www.baidu.com'));
});
这样是正常的,但是在此版本中,就会收到废弃警告
PHP Deprecated: Swoole\Event::rshutdown(): Event::wait() in shutdown function is deprecated in Unknown on line 0
推荐使用Coroutine\run
来代替这种方式:
Swoole\Coroutine\run(function () {
var_dump(Co\System::gethostbyname('www.baidu.com'));
});
Swoole\Coroutine\run(function () {
go(function () {
var_dump(Co\System::gethostbyname('www.baidu.com'));
});
go(function () {
var_dump(Co\System::gethostbyname('www.zhihu.com'));
});
});
默认启用 Coroutine
hook使用了上面所说的Coroutine\run
之后,也会迎来一个新的变更:默认启用 Coroutine
hook,即自动设置SWOOLE_HOOK_ALL
use Swoole\Runtime;
Swoole\Coroutine\run(function () {
$flags = Runtime::getHookFlags();
assert($flags === SWOOLE_HOOK_ALL);
var_dump($flags);
});
当然也可以自行设置所需要的 flag
use Swoole\Runtime;
Runtime::setHookFlags(SWOOLE_HOOK_TCP);
Swoole\Coroutine\run(function () {
$flags = Runtime::getHookFlags();
assert($flags === SWOOLE_HOOK_TCP);
var_dump($flags);
});
使用协程时禁用不安全功能,包括 pcntl_fork
/pcntl_wait
/pcntl_waitpid
/pcntl_sigtimedwait
Swoole\Coroutine\run(function () {
$pid = pcntl_fork();
var_dump($pid);
});
在此版本使用上面的示例代码,你将会得到一个 Warning
错误
PHP Warning: pcntl_fork() has been disabled for security reasons
移除了 session_id
的最大限制,不再重复将 Server 的 session_id
从 int24
改为了 int64
,这样可以持续自增,永不重复。
之前的int24
时,session_id
大约可以到 1600 万就可能会出现重复的问题。
在这个版本中最大的变化莫过于支持了原生 curl
协程客户端,有什么用呢?
用过 SWOOLE_HOOK_CURL
的小伙伴应该知道,有一些不支持的选项,同时还会因为部分 SDK 的不兼容导致一些错误,例如:
PHP Notice: Object of class Swoole\Curl\Handler could not be converted to int
PHP Warning: curl_multi_add_handle() expects parameter 2 to be resource, object given
原因是 hook 后的 curl
不再是一个 resource
类型,而是 object
类型。
PHP8
中 curl
不再是 resource
类型,而是 object
类型以及经常使用的阿里云 OSS SDK 也是不支持SWOOLE_HOOK_CURL
的,会遇到一些奇奇怪怪的
那么从 v4.6.0
版本开始就可以使用 SWOOLE_HOOK_NATIVE_CURL
代替 SWOOLE_HOOK_CURL
,来解决以上提到的问题
使用SWOOLE_HOOK_NATIVE_CURL
需要在编译 Swoole 扩展时增加 --enable-swoole-curl 编译参数,开启该选项后将自动设置 SWOOLE_HOOK_NATIVE_CURL
,关闭 SWOOLE_HOOK_CURL
,同时 SWOOLE_HOOK_ALL
也会包含 SWOOLE_HOOK_NATIVE_CURL
编译成功后使用--ri
查看信息,就可以看到curl-native
$ php --ri swoole | grep curl
curl-native => enabled
从下面的例子就可以看出两者的不同
Swoole\Runtime::setHookFlags(SWOOLE_HOOK_CURL);
Swoole\Coroutine\run(function () {
$curl = curl_init();
var_dump(get_class($curl), (int) $curl);
//PHP Notice: Object of class Swoole\Curl\Handler could not be converted to int
//string(19) "Swoole\Curl\Handler"
//int(1)
});
Swoole\Coroutine\run(function () {
$curl = curl_init();
var_dump($curl, (int) $curl);
//resource(4) of type (Swoole-Coroutine-cURL Handle)
//int(4)
});
SWOOLE_HOOK_SOCKETS增加了对 ext-sockets 的协程化支持
const N = 8;
$GLOBALS['time'] = [];
$s = microtime(true);
Swoole\Runtime::setHookFlags(SWOOLE_HOOK_SOCKETS);
Swoole\Coroutine\run(function () {
$n = N;
while($n--) {
go(function() {
$s = microtime(true);
$domain = 'www.baidu.com';
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock, $domain, 80);
socket_write($sock, "GET / HTTP/1.0\r\nHost: $domain\r\nConnection: close\r\nKeep-Alive: off\r\n\r\n");
$html = '';
while(true) {
$data = socket_read($sock, 8192);
if ($data == '') {
break;
}
$html .= $data;
}
socket_close($sock);
$GLOBALS['time'][] = microtime(true) - $s;
});
}
});
echo "Done\n";
var_dump(microtime(true) - $s, array_sum($GLOBALS['time']) / 3);
支持 Server 事件回调函数传递对象风格的参数默认不启用。通过设置 event_object 参数进行启用,以下事件回调将使用对象风格
onConnectonReceiveonCloseonPacketonPipeMessageonWorkerErroronTaskonFinish以 onConnect
为例,具体内容可参考文档 回调对象
$server->on('Connect', function (Swoole\Server $server, int $fd, int $reactorId) {
var_dump($fd);
});
$server->set([
'event_object' => true,
]);
$server->on('Connect', function (Swoole\Server $serv, Swoole\Server\Event $object) {
var_dump($object);
});
支持重复 header支持重复设置相同 $key
的 HTTP 头,并且 $value
支持多种类型,如 array
、object
、int
、float
,底层会进行 toString
转换,并且会移除末尾的空格以及换行
$http = new Swoole\Http\Server('0.0.0.0', 9501);
$http->on('request', function ($request, $response) {
$response->header('Test-Value', [
"a\r\n",
'd5678',
"e \n ",
null,
5678,
3.1415926,
]);
$response->header('Foo', new SplFileInfo('bar'));
});
$http->start();
$ curl -I http://127.0.0.1:9501
HTTP/1.1 200 OK
Test-Value: a
Test-Value: d5678
Test-Value: e
Test-Value: 5678
Test-Value: 3.1415926
Foo: bar
Server: swoole-http-server
Connection: keep-alive
Content-Type: text/html
Date: Wed, 06 Jan 2021 05:16:17 GMT
Content-Length: 39
协程死锁检测默认开启,可以通过在 Coroutine::set 中设置 enable_deadlock_check
进行关闭
在 EventLoop 终止后,如果存在协程死锁,底层会输出相关堆栈信息:
===================================================================
[FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
===================================================================
[Coroutine-2]
--------------------------------------------------------------------
#0 Swoole\Coroutine::printBackTrace() called at [@swoole-src/library/core/Coroutine/functions.php:74]
#1 Swoole\Coroutine\deadlock_check()
#2 curl_getinfo() called at [/mnt/c/code/php/hyperf-skeleton/vendor/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php:492]
更新日志下面是完整的更新日志
向下不兼容改动移除了session id
的最大限制,不再重复 (#3879) (@matyhtf)使用协程时禁用不安全功能,包括pcntl_fork
/pcntl_wait
/pcntl_waitpid
/pcntl_sigtimedwait
(#3880) (@matyhtf)默认启用 coroutine hook (#3903) (@matyhtf)移除不再支持 PHP7.1 (4a963df) (9de8d9e) (@matyhtf)废弃将 Event::rshutdown()
标记为已弃用,请改用 Coroutine\run (#3881) (@matyhtf)新增 API支持 setPriority/getPriority (#3876) (@matyhtf)支持 native-curl hook (#3863) (@matyhtf) (@huanghantao)支持 Server 事件回调函数传递对象风格的参数,默认不传递对象风格的参数 (#3888) (@matyhtf)支持 hook sockets 扩展 (#3898) (@matyhtf)支持重复 header (#3905) (@matyhtf)支持 SSL sni (#3908) (@matyhtf)支持 hook stdio (#3924) (@matyhtf)支持 stream_socket 的 capture_peer_cert 选项 (#3930) (@matyhtf)添加 Http\Request::create/parse/isCompleted (#3938) (@matyhtf)添加 Http\Response::isWritable (db56827) (@matyhtf)增强Server 的所有时间精度都从 int 修改为 double (#3882) (@matyhtf)在 swoole_client_select 函数里面检查 poll 函数的 EINTR 情况 (#3909) (@shiguangqi)添加协程死锁检测 (#3911) (@matyhtf)支持使用 SWOOLE_BASE 模式在另一个进程中关闭连接 (#3916) (@matyhtf)优化 Server master 进程与 worker 进程通信的性能,减少内存拷贝 (#3910) (@huanghantao) (@matyhtf)修复当 Coroutine\Channel 被关闭时,pop 出里面所有的数据 (960431d) (@matyhtf)修复使用 JIT 时的内存错误 (#3907) (@twose)修复 port->set()
dtls 编译错误 (#3947) (@Yurunsoft)修复 connection_list 错误 (#3948) (@sy-records)修复 ssl verify (#3954) (@matyhtf)修复 Table 递增和递减时不能清除所有列问题 (#3956) (@matyhtf) (@sy-records)修复使用 LibreSSL 2.7.5 编译失败 (#3962) (@matyhtf)修复未定义的常量 CURLOPT_HEADEROPT 和 CURLOPT_PROXYHEADER (swoole/library#77) (@sy-records)内核默认情况下忽略 SIGPIPE 信号 (9647678) (@matyhtf)支持同时运行 PHP 协程和 C 协程 (c94bfd8) (@matyhtf)添加 get_elapsed 测试 (#3961) (@luolaifa000)添加 get_init_msec 测试 (#3964) (@luffluo)php介绍
PHP即“超文本预处理器”,是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。利于学习,使用广泛,主要适用于Web开发领域。