Home
Download
Document
Forum
Video
Donate
Source Code
AI 助理
Sponsors
CRMEB
Apipost
腾讯云
微擎
禅道
51Talk
Products
Swoole AI 智能文档翻译器
Swoole-Compiler PHP 代码加密器
CRMEB 新零售社交电商系统
Login
Register
全部
提问
分享
讨论
建议
公告
开发框架
CodeGalaxy
发表新帖
Swoole v4.6.5 版本发布,增加原生curl multi支持
[v4.6.5](https://github.com/swoole/swoole-src/releases/tag/v4.6.5) 版本没有向下不兼容改动,主要对原生 curl hook 进行了一些增强,支持了 curl multi - 支持原生 curl multi 使用原生 curl hook 的前提是在编译 Swoole 扩展时开启`--enable-swoole-curl`选项 可以使用以下代码进行测试: ```php use Swoole\Runtime; use function Swoole\Coroutine\run; Runtime::enableCoroutine(SWOOLE_HOOK_NATIVE_CURL); run(function () { $ch1 = curl_init(); $ch2 = curl_init(); // 设置URL和相应的选项 curl_setopt($ch1, CURLOPT_URL, "http://www.baidu.com/"); curl_setopt($ch1, CURLOPT_HEADER, 0); curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch2, CURLOPT_URL, "http://www.gov.cn/"); curl_setopt($ch2, CURLOPT_HEADER, 0); curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1); $mh = curl_multi_init(); curl_multi_add_handle($mh, $ch1); curl_multi_add_handle($mh, $ch2); $active = null; // 执行批处理句柄 do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { $n = curl_multi_select($mh); if ($n != -1) { do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } $info1 = curl_multi_info_read($mh); $info2 = curl_multi_info_read($mh); $info3 = curl_multi_info_read($mh); assert($info1['msg'] === CURLMSG_DONE); assert($info2['msg'] === CURLMSG_DONE); assert($info3 === false); assert(strpos(curl_multi_getcontent($ch1),'baidu.com') !== false); assert(strpos(curl_multi_getcontent($ch2),'中央人民政府门户网站') !== false); curl_multi_remove_handle($mh, $ch1); curl_multi_remove_handle($mh, $ch2); curl_multi_close($mh); }); ``` 支持 curl multi 之后,也就间接的支持了 Guzzle,**无需更改任何代码**,即可支持。 ```php include __DIR__ . '/vendor/autoload.php'; use Swoole\Coroutine\Barrier; use Swoole\Runtime; use GuzzleHttp\Client; use GuzzleHttp\Promise; use function Swoole\Coroutine\run; use function Swoole\Coroutine\go; Runtime::enableCoroutine(SWOOLE_HOOK_NATIVE_CURL); const N = 4; run(function () { $barrier = Barrier::make(); $result = []; go(function () use ($barrier, &$result) { $client = new Client(); $promises = [ 'baidu' => $client->getAsync('http://www.baidu.com/'), 'qq' => $client->getAsync('https://www.qq.com/'), 'gov' => $client->getAsync('http://www.gov.cn/') ]; $responses = Promise\Utils::unwrap($promises); assert(strpos($responses['baidu']->getBody(),'百度') !== false); assert(strpos(iconv('gbk', 'utf-8', $responses['qq']->getBody()),'腾讯') !== false); assert(strpos($responses['gov']->getBody(),'中华人民共和国') !== false); $result['task_1'] = 'OK'; }); go(function () use ($barrier, &$result) { $client = new Client(['base_uri' => 'http://httpbin.org/']); $n = N; $data = $promises = []; while ($n--) { $key = 'req_' . $n; $data[$key] = uniqid('swoole_test'); $promises[$key] = $client->getAsync('/base64/' . base64_encode($data[$key])); } $responses = Promise\Utils::unwrap($promises); $n = N; while ($n--) { $key = 'req_' . $n; assert($responses[$key]->getBody() === $data[$key]); } $result['task_2'] = 'OK'; }); Barrier::wait($barrier); assert($result['task_1'] === 'OK'); assert($result['task_2'] === 'OK'); echo 'Done' . PHP_EOL; }); ``` 同时也还添加了一些 Guzzle 的单元测试。 - 允许在使用 HTTP/2 的 Response 中使用数组设置 headers 从 `v4.6.0` 版本开始 Swoole\Http\Response 支持重复设置相同 `$key` 的 `HTTP` 头,并且 `$value` 支持多种类型,如 `array`、`object`、`int`、`float`,底层会进行 `toString` 转换,并且会移除末尾的空格以及换行。 但是未支持 HTTP/2 的,详情见 issue [#4133](https://github.com/swoole/swoole-src/issues/4133) 在此版本中也进行了支持: ```php $http = new Swoole\Http\Server('127.0.0.1', 9501); $http->set(['open_http2_protocol' => true]); $http->on('request', function ($request, $response) { $response->header('Test-Value', [ "a\r\n", 'd5678', "e \n ", null, 5678, 3.1415926, ]); $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>"); }); $http->start(); ``` 可以使用以上代码进行测试,并使用 curl 命令进行测试结果 ```bash $ curl --http2-prior-knowledge -v http://localhost:9501 * Trying ::1... * TCP_NODELAY set * Connection failed * connect to ::1 port 9501 failed: Connection refused * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 9501 (#0) * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x7fe9e9009200) > GET / HTTP/2 > Host: localhost:9501 > User-Agent: curl/7.64.1 > Accept: */* > * Connection state changed (MAX_CONCURRENT_STREAMS == 128)! < HTTP/2 200 < test-value: a < test-value: d5678 < test-value: e < test-value: 5678 < test-value: 3.1415926 < server: swoole-http-server < date: Fri, 09 Apr 2021 11:04:39 GMT < content-type: text/html < content-length: 28 < * Connection #0 to host localhost left intact <h1>Hello Swoole. #6944</h1>* Closing connection 0 ``` ## 更新日志 下面是完整的更新日志: ### 新增 API - 在 WaitGroup 中增加 count 方法(swoole/library#100) (@sy-records) (@deminy) ### 增强 - 支持原生 curl multi (#4093) (#4099) (#4101) (#4105) (#4113) (#4121) (#4147) (swoole/swoole-src@cd7f51c) (@matyhtf) (@sy-records) (@huanghantao) - 允许在使用 HTTP/2 的 Response 中使用数组设置 headers ### 修复 - 修复 NetBSD 构建 (#4080) (@devnexen) - 修复 OpenBSD 构建 (#4108) (@devnexen) - 修复 illumos/solaris 构建,只有成员别名 (#4109) (@devnexen) - 修复握手未完成时,SSL 连接的心跳检测不生效 (#4114) (@matyhtf) - 修复 Http\Client 使用代理时`host`中存在`host:port`产生的错误 (#4124) (@Yurunsoft) - 修复 Swoole\Coroutine\Http::request 中 header 和 cookie 的设置 (swoole/library#103) (@leocavalcante) (@deminy) ### 内核 - 支持 BSD 上的 asm context (#4082) (@devnexen) - 在 FreeBSD 下使用 arc4random_buf 来实现 getrandom (#4096) (@devnexen) - 优化 darwin arm64 context:删除 workaround 使用 label (#4127) (@devnexen) ### 测试 - 添加 alpine 的构建脚本 (#4104) (@limingxinleo) ![](https://cdn.jsdelivr.net/gh/sy-records/staticfile/images/swoole/wechat.png)
发布于3年前 · 12 次浏览 · 来自
分享
鲁飞
[v4.6.5](https://github.com/swoole/swoole-src/releases/tag/v4.6.5) 版本没有向下不兼容改动,主要对原生 curl hook 进行了一些增强,支持了 curl multi - 支持原生 curl multi 使用原生 curl hook 的前提是在编译 Swoole 扩展时开启`--enable-swoole-curl`选项 可以使用以下代码进行测试: ```php use Swoole\Runtime; use function Swoole\Coroutine\run; Runtime::enableCoroutine(SWOOLE_HOOK_NATIVE_CURL); run(function () { $ch1 = curl_init(); $ch2 = curl_init(); // 设置URL和相应的选项 curl_setopt($ch1, CURLOPT_URL, "http://www.baidu.com/"); curl_setopt($ch1, CURLOPT_HEADER, 0); curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch2, CURLOPT_URL, "http://www.gov.cn/"); curl_setopt($ch2, CURLOPT_HEADER, 0); curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1); $mh = curl_multi_init(); curl_multi_add_handle($mh, $ch1); curl_multi_add_handle($mh, $ch2); $active = null; // 执行批处理句柄 do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { $n = curl_multi_select($mh); if ($n != -1) { do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } $info1 = curl_multi_info_read($mh); $info2 = curl_multi_info_read($mh); $info3 = curl_multi_info_read($mh); assert($info1['msg'] === CURLMSG_DONE); assert($info2['msg'] === CURLMSG_DONE); assert($info3 === false); assert(strpos(curl_multi_getcontent($ch1),'baidu.com') !== false); assert(strpos(curl_multi_getcontent($ch2),'中央人民政府门户网站') !== false); curl_multi_remove_handle($mh, $ch1); curl_multi_remove_handle($mh, $ch2); curl_multi_close($mh); }); ``` 支持 curl multi 之后,也就间接的支持了 Guzzle,**无需更改任何代码**,即可支持。 ```php include __DIR__ . '/vendor/autoload.php'; use Swoole\Coroutine\Barrier; use Swoole\Runtime; use GuzzleHttp\Client; use GuzzleHttp\Promise; use function Swoole\Coroutine\run; use function Swoole\Coroutine\go; Runtime::enableCoroutine(SWOOLE_HOOK_NATIVE_CURL); const N = 4; run(function () { $barrier = Barrier::make(); $result = []; go(function () use ($barrier, &$result) { $client = new Client(); $promises = [ 'baidu' => $client->getAsync('http://www.baidu.com/'), 'qq' => $client->getAsync('https://www.qq.com/'), 'gov' => $client->getAsync('http://www.gov.cn/') ]; $responses = Promise\Utils::unwrap($promises); assert(strpos($responses['baidu']->getBody(),'百度') !== false); assert(strpos(iconv('gbk', 'utf-8', $responses['qq']->getBody()),'腾讯') !== false); assert(strpos($responses['gov']->getBody(),'中华人民共和国') !== false); $result['task_1'] = 'OK'; }); go(function () use ($barrier, &$result) { $client = new Client(['base_uri' => 'http://httpbin.org/']); $n = N; $data = $promises = []; while ($n--) { $key = 'req_' . $n; $data[$key] = uniqid('swoole_test'); $promises[$key] = $client->getAsync('/base64/' . base64_encode($data[$key])); } $responses = Promise\Utils::unwrap($promises); $n = N; while ($n--) { $key = 'req_' . $n; assert($responses[$key]->getBody() === $data[$key]); } $result['task_2'] = 'OK'; }); Barrier::wait($barrier); assert($result['task_1'] === 'OK'); assert($result['task_2'] === 'OK'); echo 'Done' . PHP_EOL; }); ``` 同时也还添加了一些 Guzzle 的单元测试。 - 允许在使用 HTTP/2 的 Response 中使用数组设置 headers 从 `v4.6.0` 版本开始 Swoole\Http\Response 支持重复设置相同 `$key` 的 `HTTP` 头,并且 `$value` 支持多种类型,如 `array`、`object`、`int`、`float`,底层会进行 `toString` 转换,并且会移除末尾的空格以及换行。 但是未支持 HTTP/2 的,详情见 issue [#4133](https://github.com/swoole/swoole-src/issues/4133) 在此版本中也进行了支持: ```php $http = new Swoole\Http\Server('127.0.0.1', 9501); $http->set(['open_http2_protocol' => true]); $http->on('request', function ($request, $response) { $response->header('Test-Value', [ "a\r\n", 'd5678', "e \n ", null, 5678, 3.1415926, ]); $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>"); }); $http->start(); ``` 可以使用以上代码进行测试,并使用 curl 命令进行测试结果 ```bash $ curl --http2-prior-knowledge -v http://localhost:9501 * Trying ::1... * TCP_NODELAY set * Connection failed * connect to ::1 port 9501 failed: Connection refused * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 9501 (#0) * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x7fe9e9009200) > GET / HTTP/2 > Host: localhost:9501 > User-Agent: curl/7.64.1 > Accept: */* > * Connection state changed (MAX_CONCURRENT_STREAMS == 128)! < HTTP/2 200 < test-value: a < test-value: d5678 < test-value: e < test-value: 5678 < test-value: 3.1415926 < server: swoole-http-server < date: Fri, 09 Apr 2021 11:04:39 GMT < content-type: text/html < content-length: 28 < * Connection #0 to host localhost left intact <h1>Hello Swoole. #6944</h1>* Closing connection 0 ``` ## 更新日志 下面是完整的更新日志: ### 新增 API - 在 WaitGroup 中增加 count 方法(swoole/library#100) (@sy-records) (@deminy) ### 增强 - 支持原生 curl multi (#4093) (#4099) (#4101) (#4105) (#4113) (#4121) (#4147) (swoole/swoole-src@cd7f51c) (@matyhtf) (@sy-records) (@huanghantao) - 允许在使用 HTTP/2 的 Response 中使用数组设置 headers ### 修复 - 修复 NetBSD 构建 (#4080) (@devnexen) - 修复 OpenBSD 构建 (#4108) (@devnexen) - 修复 illumos/solaris 构建,只有成员别名 (#4109) (@devnexen) - 修复握手未完成时,SSL 连接的心跳检测不生效 (#4114) (@matyhtf) - 修复 Http\Client 使用代理时`host`中存在`host:port`产生的错误 (#4124) (@Yurunsoft) - 修复 Swoole\Coroutine\Http::request 中 header 和 cookie 的设置 (swoole/library#103) (@leocavalcante) (@deminy) ### 内核 - 支持 BSD 上的 asm context (#4082) (@devnexen) - 在 FreeBSD 下使用 arc4random_buf 来实现 getrandom (#4096) (@devnexen) - 优化 darwin arm64 context:删除 workaround 使用 label (#4127) (@devnexen) ### 测试 - 添加 alpine 的构建脚本 (#4104) (@limingxinleo) ![](https://cdn.jsdelivr.net/gh/sy-records/staticfile/images/swoole/wechat.png)
赞
0
分享
收藏
提问
分享
讨论
建议
公告
开发框架
CodeGalaxy
评论
2021-04-10
徐先生
有 hook phalcon的计划吗?
赞
0
回复
2021-04-12
卡大大
curl hook和协程 HTTP/WebSocket 客户端性能什么差异吗?
赞
0
回复
微信公众号
热门内容
作者其它话题
- thinkphp5.1在使用think-swoole的时候报错unsupported option [host]
- WSL 下服务器响应数据过大无法接收
暂无回复的问答
- CodeGalaxy K3s 轻量集群节点之间如何实现负载均衡
- 关于openssl CURL WARNING swSSL_connect: SSL_connect(fd=69) failed. Error: error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small[1|394]
- 多个模型如何进行事务异常回退?
- websocket开启wss报错
- 协程tcp服务器如何使用多进程?recv()方法接收信息,打印出来的pid一直是同一个。没用使用到多进程啊。