Swoole:PHP 協程框架

Swoole 使 PHP 開發人員可以編寫高性能高并發的 TCP、UDP、Unix Socket、HTTP、 WebSocket 等服務,讓 PHP 不再局限于 Web 領域。Swoole4 協程的成熟將 PHP 帶入了前所未有的時期, 為性能的提升提供了獨一無二的可能性。Swoole 可以廣泛應用于互聯網、移動通信、云計算、 網絡游戲、物聯網(IOT)、車聯網、智能家居等領域。使用 PHP + Swoole 可以使企業 IT 研發團隊的效率大大提升,更加專注于開發創新產品。


use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function() {
    sleep(1);
});

use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function() {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $result = $redis->keys('*');
    var_dump($result);
});

use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function() {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://httpbin.org/get');
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $result = curl_exec($ch);
    curl_close($ch);
    var_dump($result);
});

use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function () {
    go(function () {
        $pdo = new PDO('mysql:host=10.66.110.163;dbname=coding_test;charset=utf8', 'coding_test', 'coding_test');
        $statement = $pdo->prepare('SELECT * FROM `coding_test`');
        $statement->execute();
        var_dump($statement->fetchAll());
    });
    go(function () {
        $mysqli = new mysqli('10.66.110.163', 'coding_test', 'coding_test', 'coding_test');
        $statement = $mysqli->prepare('SELECT `id` FROM `coding_test`');
        $statement->bind_result($id);
        $statement->execute();
        $statement->fetch();
        var_dump($id);
    });
});

use Swoole\Coroutine;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function() {
    $result = [];
    Coroutine::join([
        go(function () use (&$result) {
            $result['baidu'] = file_get_contents("https://www.baidu.com/");
        }),
        go(function () use (&$result) {
            $result['taobao'] = file_get_contents("https://www.taobao.com/");
        })
    ]);

    echo "all done\n";
});

$http = new Swoole\Http\Server('127.0.0.1', 9501);

$http->on('start', function ($server) {
    echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$http->on('request', function ($request, $response) {
    $response->header('Content-Type', 'text/plain');
    $response->end('Hello World');
});

$http->start();

$server = new Swoole\Server('127.0.0.1', 9503);

$server->on('start', function ($server) {
    echo "TCP Server is started at tcp://127.0.0.1:9503\n";
});

$server->on('connect', function ($server, $fd){
    echo "connection open: {$fd}\n";
});

$server->on('receive', function ($server, $fd, $reactor_id, $data) {
    $server->send($fd, "Swoole: {$data}");
});

$server->on('close', function ($server, $fd) {
    echo "connection close: {$fd}\n";
});

$server->start();

$server = new Swoole\Server('127.0.0.1', 9504, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);

$server->on('start', function ($server) {
    echo "UDP Server is started at udp://127.0.0.1:9504\n";
});

$server->on('packet', function ($server, $data, $clientInfo) {
    $server->sendTo($clientInfo['address'], $clientInfo['port'], "Server:{$data}");
});

$server->start();

$server = new Swoole\Websocket\Server('127.0.0.1', 9502);

$server->on('start', function ($server) {
    echo "Websocket Server is started at ws://127.0.0.1:9502\n";
});

$server->on('open', function($server, $req) {
    echo "connection open: {$req->fd}\n";
});

$server->on('message', function($server, $frame) {
    echo "received message: {$frame->data}\n";
    $server->push($frame->fd, json_encode(['hello', 'world']));
});

$server->on('close', function($server, $fd) {
    echo "connection close: {$fd}\n";
});

$server->start();

use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function() {
    $id = go(function(){
        $id = Co::getUid();
        echo "start coro $id\n";
        Co::suspend($id);
        echo "resume coro $id @1\n";
        Co::suspend($id);
        echo "resume coro $id @2\n";
    });
    echo "start to resume $id @1\n";
    Co::resume($id);
    echo "start to resume $id @2\n";
    Co::resume($id);
    echo "main\n";
});

use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function(){
    $channel = new Channel(1);
    go(function () use ($channel) {
        for($i = 0; $i < 10; $i++) {
            Coroutine::sleep(1.0);
            $channel->push(['rand' => rand(1000, 9999), 'index' => $i]);
            echo "{$i}\n";
        }
    });
    go(function () use ($channel) {
        while(true) {
            $data = $channel->pop(2.0);
            if ($data) {
                var_dump($data);
            } else {
                assert($channel->errCode === SWOOLE_CHANNEL_TIMEOUT);
                break;
            }
        }
    });
});

use Swoole\Coroutine\Socket;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;

run(function() {
    go(function () {
        $socket = new Socket(AF_INET, SOCK_DGRAM, 0);
        $socket->bind('127.0.0.1', 9503);
        $client_map = [];
        for ($c = 128; $c--;) {
            for ($n = 0; $n < 100; $n++) {
                $recv = $socket->recvfrom($peer);
                $client_uid = "{$peer['address']}:{$peer['port']}";
                $id = $client_map[$client_uid] = ($client_map[$client_uid] ?? -1) + 1;
                assert($recv === "Client: Hello #{$id}!");
                $socket->sendto($peer['address'], $peer['port'], "Server: Hello #{$id}!");
            }
        }
        $socket->close();
    });
    for ($c = 128; $c--;) {
        go(function () {
            $fp = stream_socket_client('udp://127.0.0.1:9503', $errno, $errstr, 1);
            if (!$fp) {
                echo "{$errstr} ({$errno})\n";
                return;
            }
            for ($n = 0; $n < 100; $n++) {
                fwrite($fp, "Client: Hello #{$n}!");
                $recv = fread($fp, 1024);
                list($address, $port) = explode(':', (stream_socket_get_name($fp, true)));
                assert($address === '127.0.0.1' && (int)$port === 9503);
                assert($recv === "Server: Hello #{$n}!");
            }
            fclose($fp);
        });
    }
    echo 'Done', PHP_EOL;
});

use function Swoole\Coroutine\run;

run(function(){
    $fp1 = stream_socket_client('tcp://www.baidu.com:80', $errno, $errstr, 30);
    $fp2 = stream_socket_client('tcp://www.qq.com:80', $errno, $errstr, 30);
    if (!$fp1) {
        echo "$errstr ($errno) \n";
    } else {
        fwrite($fp1, "GET / HTTP/1.0\r\nHost: www.baidu.com\r\nUser-Agent: curl/7.58.0\r\nAccept: */*\r\n\r\n");
        $r_array = [$fp1, $fp2];
        $w_array = $e_array = null;
        $n = stream_select($r_array, $w_array, $e_array, 10);
        $html = '';
        while (!feof($fp1)) {
            $html .= fgets($fp1, 1024);
        }
        fclose($fp1);
        echo strlen($html);
    }
});

$server = new Swoole\Server('127.0.0.1', 9503);

$server->set(['task_worker_num' => 4]);

$server->on('start', function ($server) {
    echo "TCP Server is started at tcp://127.0.0.1:9503\n";
});

$server->on('receive', function($server, $fd, $reactor_id, $data) {
    $task_id = $server->task('Async');
    $server->send($fd, "Dispatch AsyncTask: [id={$task_id}]\n");
});

$server->on('task', function ($server, $task_id, $reactor_id, $data) {
    echo "New AsyncTask[id={$task_id}]\n";
    $server->finish("{$data} -> OK");
});

$server->on('finish', function ($server, $task_id, $data) {
    echo "AsyncTask[{$task_id}] finished: {$data}\n";
});

$server->start();

開源、高性能、生產力

如果您有基于 Swoole 的優秀項目希望展示在官網,請掃描微信二維碼聯系我們

Yasd
Yasd 是一個 Swoole 調試器,類似 Xdebug,完美支持協程,支持斷點調試、單步追蹤、watch 變量
分布式定時任務 (Swoole Crontab)
基于 Swoole 的定時器程序,支持秒級處理,完全兼容 crontab 語法,且支持秒的配置,可使用數組規定好精確操作時間,Web 界面管理,增刪改查任務,完整的權限控制
實時視頻語音 (Webrtc)
基于 Swoole4 高性能協程的 demo 級實時視頻和語音通話方案,采用 webrtc 協議,并已經做好 p2p 打洞,中繼服務器,演示地址:https://webrtc.dingjw.com/room.php?cid=2
MyCMS
MyCMS 是一款基于 Laravel 開發開源免費的商城博客 CMS 建站系統,通過集成 Swoole 大幅度提升系統的性能,功能和性能兼得
Markdown文檔系統
軟擎文檔系統是基于 Swoole + Rangine 框架開發的開源版 MarkDown 文檔管理系統,不同于 docsify.js 等前端文檔系統,本文檔系統是偏后端的文檔系統,對于廣大PHPer來說更加友好。支持多用戶協同操作,管理員審核發布等功能。 讓您的工作更高效,更智慧。
Swoole Worker
Swoole Worker是基于Swoole4開發的一款分布式長連接開發框架。常駐內存,協程,高性能高并發;分布式部署,橫向擴容,使得能支持龐大的連接數;無感知安全重啟,無縫升級代碼;接口豐富,支持單個發送,分組發送,群發廣播等接口。
店滴云開源框架
店滴云是針對多商戶業務開發的一套管理cms,支持多運營主體,單運營主體運營開發。基于世界上最好的語言php和yii開發,深度集成swoole,滿足需要http/tcp/mqtt等多種協議的業務場景,官方提供智能門鎖,智能開關成熟的解決方案。采用最新的vue開發技術作為中后臺管理,多終端開發框架uniapp打造,旨在讓開發更有趣味和成就感,希望可以助力更多的中小企業實現業績增長,技術創新和持續發展。官方依賴于店滴云先后開發了疫情大數據監測,企業外呼,im客服,多商戶分銷,外賣點餐,政企黨建等系統。
MoChat
MoChat - 基于 Hyperf 框架的國內首款完全開源的 PHP 企業微信管理系統
xlswriter
xlswriter是一個 PHP C 擴展,支持 Swoole 協程環境,可用于在 Excel 2007+ XLSX 文件中讀取數據,插入多個工作表,寫入文本、數字、公式、日期、圖表、圖片和超鏈接。
HCMS
Hcms 是一個基于 Hyperf 框架的項目開發管理系統 , 在Hyperf超高速且靈活的特性加持下,構建一個快速開發、模塊復用的項目開發管理系統。
LaravelS
LaravelS 是 Swoole 和 Laravel/Lumen 之間開箱即用的適配器,內置 HTTP/WebSocket Server,支持 TCP/UDP Server、自定義進程、異步的事件監聽、異步任務、毫秒級定時任務、平滑Reload等特性,讓 Laravel 如虎添翼。
ShopXO開源商城
ShopXO企業級免費開源電商系統!求實進取、創新專注、自主研發、國內領先企業級電商系統解決方案。遵循MIT開源協議發布,無需授權、可商用、可二次開發、滿足99%的電商運營需求。支持PC+H5、支付寶小程序、微信小程序、百度小程序、頭條&抖音小程序、QQ小程序、APP等...支持多倉庫、多商戶、線下門店模式運營(組件插件化、即插即用),可視化DIY拖拽裝修。多端統一客服系統采用Swoole高性能WebSocket構建。
電商系統 CRMEB Pro
CRMEB Pro采用Tp6 + Swoole+redis高性能框架開發;是一款高性能、高并發、高可用的私域客戶關系管理(CRM)+營銷電商(EB)系統;助力品牌商家實現公域引流轉化私域沉淀,全渠道智能化經營。系統基于異步事件驅動和協程的并行網絡通信引擎,充分利用了底層的epoll / kqueue實現網絡事件請求處理;通過 Swoole協程異步處理數據,徹底解決了PHP高并發處理問題;通過集群部署,進一步提升系統性能。是品牌電商系統的第一選擇!
物聯網(IOT)解決方案
MQTT 是一個客戶端服務端架構的發布 / 訂閱模式的消息傳輸協議。它的設計思想是輕巧、開放、簡單、規范,易于實現。這些特點使得它對很多場景來說都是很好的選擇,特別是對于受限的環境如機器與機器的通信(M2M)以及物聯網環境(IoT)。可以使用 Swoole 作為 MQTT 服務端或客戶端,實現一套完整物聯網(IOT)解決方案
魔獸世界
魔獸模擬游戲服務器,項目采用 PHP 開發,TCP 長連接基于 Swoole,支持鑒權,角色的創建,地圖的加載,NPC 和生物的構建及各種眼花繚亂的物品和技能等等
ZooKeeper
基于 Swoole 協程的PHP ZooKeeper客戶端
PaySDK
PHP 集成支付 SDK ,集成了支付寶、微信支付的支付接口和其它相關接口的操作。支持 php-fpm 和 Swoole,所有框架通用。
斗地主
基于 Swoole + Hyperf 框架開發 demo 級的斗地主游戲,實現斗地主游戲服務端邏輯,并采用原生 js 和 WebSocket 實現簡單的客戶端打牌邏輯,可以做到簡單的玩斗地主游戲
ThinkCMF
ThinkCMF 是一款基于 ThinkPHP+Mysql 開發的 CMS,完美支持 Swoole,框架自身提供基礎的管理功能,而開發者可以根據自身的需求以應用的形式進行擴展。每個應用都能獨立的完成自己的任務,也可通過系統調用其他應用進行協同工作。在這種運行機制下,開發商場應用的用戶無需關心開發 SNS 應用時如何工作的,但他們之間又可通過系統本身進行協調,大大的降低了開發成本和溝通成本
HyperfCMS
HyperfCMS 是基于 Swoole+Hyperf 框架前后端分離架構的一套開源且完美的建站系統,擁有簡單大氣設計、友好的交互體驗、清晰明了的代碼規范。組件化的封裝應用,編寫復雜的管理應用,效率是質的提升、時間成倍縮短,人員可以減半,事半功倍。可以提供定制化服務!
PHP 微服務(Micro Service)
Hyperf 是基于 Swoole 4.4+ 實現的高性能、高靈活性的 PHP 協程框架,內置協程服務器及大量常用的組件,性能較傳統基于 PHP-FPM 的框架有質的提升,提供超高性能的同時,也保持著極其靈活的可擴展性,標準組件均基于 PSR 標準實現,基于強大的依賴注入設計,保證了絕大部分組件或類都是可替換與可復用的
Ain't Queue 異步隊列
Ain't Queue 借助 Swoole 提供的便捷多進程 API 和 CSP 編程能力實現了主進程+監控進程+多工作進程的進程模型,并且提供了各類事件自定義注冊的能力(隊列監控、快照記錄、任務中間件等)。默認使用 Redis 驅動,全原子操作,可延時可重試,自帶漂亮的儀表盤,穩定可靠,已經在公司生產環境使用。
基于 Swoole 的多進程隊列系統
基于 Swoole 的多進程隊列系統,Manager 進程管理子進程,Master 進程監聽隊列分發任務,Worker 進程執行任務, 多進程、低延時(最低毫秒級)、高可用、低資源占用、可多服務器分布式部署。可與 Laravel、ThinkPHP 等框架配合使用。默認 Redis 驅動,原子性操作,支持延時投遞、錯誤重試、自定義超時,支持后臺守護運行,無需其余進程管理工具。提供多種命令,方便管理及查詢進程狀態、任務狀態。
Mysql Proxy(Mysql中間件)
一個基于 MySQL 協議,Swoole 開發的 MySQL 數據庫連接池,支持讀寫分離支持數據庫連接池,能夠有效解決 PHP 帶來的數據庫連接瓶頸,支持 SQL92 標準,采用協程調度,遵守 MySQL 原生協議,跨語言,跨平臺的通用中間件代理,支持 MySQL 事務,完美兼容 MySQL5.5 - 8.0

聯系我們

聯系我們

官方公眾號

官方公眾號

源代碼

Swoole 特性

Swoole 使用 C/C++ 語言編寫,提供了 PHP 語言的異步多線程服務器、異步 TCP/UDP 網絡客戶端、異步 MySQL、異步 Redis、數據庫連接池、AsyncTask、消息隊列、毫秒定時器、異步文件讀寫、異步 DNS 查詢。 Swoole 內置了 Http/WebSocket 服務器端/客戶端、Http2.0 服務器端。

除了異步 IO 的支持之外,Swoole 為 PHP 多進程的模式設計了多個并發數據結構和 IPC 通信機制,可以大大 簡化多進程并發編程的工作。其中包括了原子計數器、Table、Channel、Lock、進程間通信 IPC 等豐富的功能特性。

Swoole4.0 支持了類似 Go 語言的協程,可以使用完全同步的代碼實現異步程序。PHP 代碼無需額外增加任何 關鍵詞,底層自動進行協程調度,實現異步 IO。