中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP如何實現HTTP服務器

發布時間:2023-02-16 09:29:00 來源:億速云 閱讀:133 作者:iii 欄目:開發技術

這篇文章主要介紹“PHP如何實現HTTP服務器”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“PHP如何實現HTTP服務器”文章能幫助大家解決問題。

    PHP并非不能實現HTTP服務,一般來講,這叫網絡編程或Socket編程。在學習到其他語言的這部分的時候,一般的思路就是如何監聽TCP實現一個服務器,并處理HTTP協議。

    PHP也可以這樣做,同時一般伴隨著高性能這樣的關鍵字出現。

    原生Socket編程

    我們可以通過PHP的Socket函數,很簡單的實現出HTTP服務。

    function run()
    {
        //創建服務端的socket套接流,net協議為IPv4,protocol協議為TCP
        $socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
        /*綁定接收的套接流主機和端口,與客戶端相對應*/
        if(socket_bind($socket,"0.0.0.0", 9502) == false){
            echo 'server bind fail:'.socket_strerror(socket_last_error());exit();
        }
        //監聽套接流
        if(socket_listen($socket,4)==false){
            echo 'server listen fail:'.socket_strerror(socket_last_error());exit();
        }
        //非阻塞
        socket_set_nonblock($socket);
        call_user_func('onAccept',$socket);
    }
    run();

    然后通過Socket處理收到的數據以及作出響應:

    function onMessage($connection)
    {
        //拼裝返回的html內容
        $content = '<html><title>hello,world</title><body>hello,world,http</body></html>';
        //拼裝頭信息
        $header = '';
        $header .= "HTTP/1.1 200 OK\r\n";
        $header .= "Date: ".gmdate('D, d M Y H:i:s T')."\r\n";
        $header .= "Content-Type: text/html;charset=utf-8\r\n";
        $header .= "Content-Length: ".strlen($content)."\r\n\r\n";//必須2個\r\n表示頭部信息結束
        $header .= $content;
        socket_write($connection,$header,strlen($header));
    }
    function onAccept($socket)
    {
        //接收客戶端傳遞過來的信息
        while(true)
        {
            $accept_resource = socket_accept($socket);
            if($accept_resource !== false)
            {
                $string = socket_read($accept_resource,1024);
                echo 'server receive is :'.$string.PHP_EOL;
                if($string != false)
                {
                    call_user_func('onMessage',$accept_resource);
                }
            }
        }
    }

    流行項目

    實際上,PHP有很多在項目都在實現HTTP服務器,而且他們一般也都宣稱是高性能的。

    Workerman系

    Workerman是一款純PHP開發的開源高性能的PHP 應用容器。幾乎能夠實現任何類型的網絡編程,并且內置了一個HTTP協議。

    $worker = new Worker('http://0.0.0.0:1221');

    Workerman的官方在21年出品了Webman,一個基于Workerman實現的高性能HTTP服務框架。替代傳統PHP-FPM架構,提供高性能的HTTP服務。可以用來開發網站、接口、微服務。

    Webman實際上是一個開發框架,項目的目錄結構都已經設定好了,按照文檔開發就行,最后只要通過命令就能運行起來。

    php start.php start

    Webman支持是一個MVC框架,支持命名空間自動加載,所以代碼像這樣:

    <?php
    namespace app\controller;
    use support\Request;
    class UserController
    {
        public function hello(Request $request)
        {
            $default_name = 'webman';
            // 從get請求里獲得name參數,如果沒有傳遞name參數則返回$default_name
            $name = $request->get('name', $default_name);
            // 向瀏覽器返回字符串
            return response('hello ' . $name);
        }
    }

    除了高性能等特點,他的上手難度很低,并且風格與現代的MVC風格一致,支持PSR標準,代碼精簡高效。如果你是ThinkPHP的開發者,你會發現很容易上手Webman。

    Swoole系

    說道高性能HTTP服務,總是繞不開swoole的,他也是國內最早火熱起來的PHP高性能解決方案。

    使用swoole實現HTTP服務的代碼也很簡單:

    $http = new Swoole\Http\Server('0.0.0.0', 9501);
    $http->on('Request', function ($request, $response) {
        $response->header('Content-Type', 'text/html; charset=utf-8');
        $response->end('<h2>Hello Swoole. #' . rand(1000, 9999) . '</h2>');
    });
    $http->start();

    swoole實際上是一個PHP的擴展,近幾年基于他發展起了很多的高性能框架,比如easyswoole、Hyperf、Swoft、MixPHP等等。它們都基于Swoole實現框架,可以很容易的創建完整度很成熟的系統。

    ReactPHP系

    ReactPHP 是用于 PHP 事件驅動編程的底層庫。也可以用來實現各類網絡編程,包括HTTP服務。用它實現HTTP服務也很簡單:

    require __DIR__ . '/vendor/autoload.php';
    $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
        return React\Http\Message\Response::plaintext(
            "Hello World!\n"
        );
    });
    $socket = new React\Socket\SocketServer('127.0.0.1:8080');
    $http->listen($socket);
    echo "Server running at http://127.0.0.1:8080" . PHP_EOL;

    它是一個底層庫,一般而言,所有PSR的框架都可以基于他運行,替換PHP-FPM。所以他也提供了各個流行框架的接入方案,包括laravel、symfony等,基于ReactPHP,開發了一個PHP-PM項目。

    PHP-PM 是 PHP 應用程序的進程管理器、增壓器和負載平衡器。

    可以直接通過命令運行:

    ppm start --bootstrap=laravel --app-env=prod --debug=0 --logging=0 --workers=20

    實際上ReactPHP是個很有趣的項目,比如IP電視服務器、終端shell、Mqtt的server、PHP版的Redis、一個GUI框架、比特幣P2P網絡等等,以后有機會給大家介紹介紹。

    AMPHP系

    AMPHP 是 PHP 的高質量、事件驅動庫的集合,在設計時考慮了纖維和并發性。

    基于AMPHP實現的HTTP服務框架叫amphp/http-server。使用它也可以快速實現一個穩定高性能的HTTP服務。

    use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
    use Amp\Http\Server\SocketHttpServer;
    use Amp\Http\Server\Request;
    use Amp\Http\Server\Response;
    use Amp\Http\Status;
    use Amp\Socket\Server;
    use Psr\Log\NullLogger;
    // Run this script, then visit http://localhost:1337/ in your browser.
    Amp\Loop::run(function () {
        $sockets = [
            Server::listen("0.0.0.0:1337"),
            Server::listen("[::]:1337"),
        ];
        $server = new SocketHttpServer($sockets, new ClosureRequestHandler(function (Request $request) {
            return new Response(Status::OK, [
                "content-type" => "text/plain; charset=utf-8"
            ], "Hello, World!");
        }), new NullLogger);
        yield $server->start();
        // Stop the server gracefully when SIGINT is received.
        // This is technically optional, but it is best to call Server::stop().
        Amp\Loop::onSignal(SIGINT, function (string $watcherId) use ($server) {
            Amp\Loop::cancel($watcherId);
            yield $server->stop();
        });
    });

    AMPHP也實現了很多有趣的項目,比如Mysql的客戶端,能夠實現連接池等特性。

    swow

    swow是一個基于協程的跨平臺并發I/O引擎,關注并發IO。

    官方給出的HTTP例子代碼行數比較多,主要是展示了HTTP請求支持的每個階段的操作方法,代碼也是很簡潔的。

    declare(strict_types=1);
    use Swow\Buffer;
    use Swow\Coroutine;
    use Swow\Http\Parser;
    use Swow\Http\ParserException;
    use Swow\Socket;
    use Swow\SocketException;
    $host = getenv('SERVER_HOST') ?: '127.0.0.1';
    $port = (int) (getenv('SERVER_PORT') ?: 9764);
    $backlog = (int) (getenv('SERVER_BACKLOG') ?: 8192);
    $multi = (bool) (getenv('SERVER_MULTI') ?: false);
    $bindFlag = Socket::BIND_FLAG_NONE;
    $server = new Socket(Socket::TYPE_TCP);
    if ($multi) {
        $server->setTcpAcceptBalance(true);
        $bindFlag |= Socket::BIND_FLAG_REUSEPORT;
    }
    $server->bind($host, $port, $bindFlag)->listen($backlog);
    while (true) {
        try {
            $connection = $server->accept();
        } catch (SocketException $exception) {
            break;
        }
        Coroutine::run(static function () use ($connection): void {
            $buffer = new Buffer(Buffer::COMMON_SIZE);
            $parser = (new Parser())->setType(Parser::TYPE_REQUEST)->setEvents(Parser::EVENT_BODY);
            $parsedOffset = 0;
            $body = null;
            try {
                while (true) {
                    $length = $connection->recv($buffer, $buffer->getLength());
                    if ($length === 0) {
                        break;
                    }
                    while (true) {
                        $parsedOffset += $parser->execute($buffer, $parsedOffset);
                        if ($parser->getEvent() === $parser::EVENT_NONE) {
                            $buffer->truncateFrom($parsedOffset);
                            $parsedOffset = 0;
                            break; /* goto recv more data */
                        }
                        if ($parser->getEvent() === Parser::EVENT_BODY) {
                            $body ??= new Buffer(Buffer::COMMON_SIZE);
                            $body->write(0, $buffer, $parser->getDataOffset(), $parser->getDataLength());
                        }
                        if ($parser->isCompleted()) {
                            $response = sprintf(
                                "HTTP/1.1 200 OK\r\n" .
                                "Connection: %s\r\n" .
                                "Content-Length: %d\r\n\r\n" .
                                '%s',
                                $parser->shouldKeepAlive() ? 'Keep-Alive' : 'Closed',
                                $body ? $body->getLength() : 0,
                                $body ?: ''
                            );
                            $connection->send($response);
                            $body?->clear();
                            break; /* goto recv more data */
                        }
                    }
                    if (!$parser->shouldKeepAlive()) {
                        break;
                    }
                }
            } catch (SocketException $exception) {
                echo "No.{$connection->getFd()} goaway! {$exception->getMessage()}" . PHP_EOL;
            } catch (ParserException $exception) {
                echo "No.{$connection->getFd()} parse error! {$exception->getMessage()}" . PHP_EOL;
            }
            $connection->close();
        });
    }

    關于“PHP如何實現HTTP服務器”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    通渭县| 独山县| 大关县| 新平| 栾城县| 通江县| 大悟县| 靖宇县| 开远市| 锡林郭勒盟| 建昌县| 汕头市| 马边| 乌拉特中旗| 当雄县| 永和县| 德安县| 旺苍县| 札达县| 桑日县| 象州县| 东兰县| 衡山县| 德钦县| 青州市| 娄烦县| 乐亭县| 雷波县| 汝州市| 凤台县| 朔州市| 昌都县| 福鼎市| 贡嘎县| 龙江县| 马公市| 京山县| 库车县| 无为县| 楚雄市| 嘉义县|