Swoole v4.6.0 版本發佈,支持原生 curl 協程客戶端

Swoole v4.6.0 版本發佈了,一樣也是 2021 年的首個版本更新。php

做爲一個 y 版本發佈,這次更新也包含了不兼容的修改以及許多的新功能,下面就來看一看都有哪些改動?html

向下不兼容改動

  1. v4.6.0 版本開始將再也不支持 PHP7.1

PHP 官方對於 PHP7.1 的支持也早已在 2019 年末結束。react

  1. Event::rshutdown() 標記爲已棄用,請改用 Coroutine\run

在以前的版本中,若是在index.php中直接使用go建立協程安全

go(function () {
    var_dump(Co\System::gethostbyname('www.baidu.com'));
});

這樣是正常的,可是在此版本中,就會收到廢棄警告bash

PHP Deprecated:  Swoole\Event::rshutdown(): Event::wait() in shutdown function is deprecated in Unknown on line 0

推薦使用Coroutine\run來代替這種方式:swoole

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'));
    });
});
  1. 默認啓用 Coroutine hook

使用了上面所說的Coroutine\run以後,也會迎來一個新的變動:默認啓用 Coroutine hook,即自動設置SWOOLE_HOOK_ALLsession

use Swoole\Runtime;

Swoole\Coroutine\run(function () {
    $flags = Runtime::getHookFlags();
    assert($flags === SWOOLE_HOOK_ALL);
    var_dump($flags);
});

固然也能夠自行設置所須要的 flagdom

use Swoole\Runtime;

Runtime::setHookFlags(SWOOLE_HOOK_TCP);
Swoole\Coroutine\run(function () {
    $flags = Runtime::getHookFlags();
    assert($flags === SWOOLE_HOOK_TCP);
    var_dump($flags);
});
  1. 使用協程時禁用不安全功能,包括 pcntl_fork/pcntl_wait/pcntl_waitpid/pcntl_sigtimedwait
Swoole\Coroutine\run(function () {
    $pid = pcntl_fork();
    var_dump($pid);
});

在此版本使用上面的示例代碼,你將會獲得一個 Warning 錯誤curl

PHP Warning:  pcntl_fork() has been disabled for security reasons
  1. 移除了 session_id 的最大限制,再也不重複

將 Server 的 session_idint24 改成了 int64 ,這樣能夠持續自增,永不重複。socket

以前的int24時,session_id大約能夠到 1600 萬就可能會出現重複的問題。

新增 API & 加強

原生 curl 協程客戶端 (SWOOLE_HOOK_NATIVE_CURL)

在這個版本中最大的變化莫過於支持了原生 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 類型。

出現這種問題也建議聯繫 SDK 方修改代碼,由於在 PHP8curl 再也不是 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

pecl 的 v4.6.0 版本暫時沒有增長這個選項,請使用手動編譯開啓,下個版本中會增長。

編譯成功後使用--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 參數進行啓用,如下事件回調將使用對象風格

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 支持多種類型,如 arrayobjectintfloat,底層會進行 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)

Swoole官方公衆號

相關文章
相關標籤/搜索