Swoole 中使用 WebSocket 異步服務器、WebSocket 協程服務器


WebSocket 異步風格服務器

WebSocket\Server 繼承自 Http\Server,所以 Http\Server 提供的所有 API 和配置項都可以使用。

# ws_server.php

class WebSocket
{
    public $server;

    public function __construct()
    {
        // 創建websocket服務器對象,監聽0.0.0.0:9502端口
        $this->server = new Swoole\WebSocket\Server("0.0.0.0", 9502);

        // 設置服務器運行參數
        $this->server->set(array(
            'daemonize'     => 1,  // 作為守護進程運行,需同時設置log_file
            'log_file'      => '/www/logs/swoole.log',  // 指定標准輸出和錯誤日志文件
        ));
        
        // 監聽WebSocket連接打開事件
        $this->server->on('open', function ($ws, $request) {
            var_dump($request->fd, $request->get, $request->server);
            $ws->push($request->fd, "hello, welcome\n");
        });

        // 監聽WebSocket消息事件
        $this->server->on('message', function ($ws, $frame) {
            echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
            $ws->push($frame->fd, "server: {$frame->data}");
        });

        // 監聽WebSocket連接關閉事件
        $this->server->on('close', function ($ws, $fd) {
            echo "client {$fd} is closed\n";
        });

        // 通過 HTTP 請求向所有用戶推送消息
        $this->server->on('request', function ($request, $response) {
            foreach ($this->server->connections as $fd) {
                // 檢查連接是否為有效的 WebSocket 客戶端連接,避免push失敗
                if ($this->server->isEstablished($fd)) {
                    $this->server->push($fd, $request->get['message']);
                }
            }
        });

        $this->server->start();
    }
}

// 啟動 WebSocket 服務器
new WebSocket();

運行並測試 WebSocket 異步風格服務器

# 如果程序已經運行,先結束進程
kill -9 11591

# 在 cli 命令行環境運行服務端
php ws_server.php

# 查看服務器監聽的端口
netstat -an | grep 9502

WebSocket JS客戶端

# index.js

var wsServer = 'ws://127.0.0.1:9502';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
    console.log("Connected to WebSocket server.");
    websocket.send('hello ws!');
};

websocket.onclose = function (evt) {
    console.log("Disconnected");
};

websocket.onmessage = function (evt) {
    console.log('Retrieved data from server: ' + evt.data);
};

websocket.onerror = function (evt, e) {
    console.log('Error occured: ' + evt.data);
};

客戶端

  • Chrome/Firefox/ 高版本 IE/Safari 等瀏覽器內置了 JS 語言的 WebSocket 客戶端
  • 微信小程序開發框架內置的 WebSocket 客戶端
  • 異步 IOPHP 程序中可以使用 Swoole\Coroutine\Http 作為 WebSocket 客戶端
  • Apache/PHP-FPM 或其他同步阻塞的 PHP 程序中可以使用 swoole/framework 提供的同步 WebSocket 客戶端
  • WebSocket 客戶端不能與 WebSocket 服務器通信

WebSocket 協程風格服務器

Co\run(function () {
    $server = new Co\Http\Server("127.0.0.1", 9502, false);

    // 設置服務器運行參數
    $server->set(array(
        'daemonize'     => 1,  // 作為守護進程運行,需同時設置log_file
        'log_file'      => '/www/logs/swoole.log',  // 指定標准輸出和錯誤日志文件
    ));

    $server->handle('/websocket', function ($request, $ws) {
        // 向客戶端發送 WebSocket 握手消息
        $ws->upgrade();
        
        // 循環處理消息的接收和發送
        while (true) {
            // 接收 WebSocket 消息幀,會掛起當前協程,等待數據到來時再恢復協程的執行
            $frame = $ws->recv();
            if ($frame === false) {
                echo "error : " . swoole_last_error() . "\n";
                break;
            } else if ($frame == '') {
                break;
            } else {
                if ($frame->data == "close") {
                    $ws->close();
                    return;
                }
                
                // 向對端發送數據幀
                $ws->push("Hello {$frame->data}!");
                $ws->push("How are you, {$frame->data}?");
            }
        }
    });

    $server->handle('/', function ($request, $response) {
        $response->end(<<<HTML
<h1>Swoole WebSocket Server</h1>
<script>
var wsServer = 'ws://127.0.0.1:9502/websocket';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
    console.log("Connected to WebSocket server.");
    websocket.send('hello');
};

websocket.onclose = function (evt) {
    console.log("Disconnected");
};

websocket.onmessage = function (evt) {
    console.log('Retrieved data from server: ' + evt.data);
};

websocket.onerror = function (evt, e) {
    console.log('Error occured: ' + evt.data);
};
</script>
HTML
        );
    });

    $server->start();
});

WebSocket 協程客戶端

官方建議使用 Saber


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM