PHP如何实现HTTP服务器

news2024/11/25 8:18:23

一般来讲,PHP很少谈到“实现HTTP服务”的说法,因为从早期的CGI到后来的PHP-FPM,官方已经给出了最稳定的HTTP解决方案,你只要配合一个Apache或Nginx类的服务器就能实现稳定的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('<h1>Hello Swoole. #' . rand(1000, 9999) . '</h1>');
});

$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服务的项目。这里不多做介绍了。虽然我们谈到PHP的时候,很少谈到网络编程,甚至在入门教程中根本就没有网络编程这节课。但是使用PHP做网络编程的各项应用已经很火热了。

在入门其他语言是一定有一节课程是学习网络编程的,做PHP教程的也应该考虑考虑增加这部分课程了。

原文标题:PHP如何实现HTTP服务器

原文地址:https://phpreturn.com/index/a63ead74ab71f6.html

原文平台:PHP武器库

版权声明:本文由phpreturn.com(PHP武器库官网)原创和首发,所有权利归phpreturn(PHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/346251.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

知识付费小程序怎么做_分享知识付费小程序的作用

在线知识付费产业的主要业务逻辑是基于用户的主动学习需求&#xff0c;为其提供以跨领域基础知识与技能为核心的在线知识服务&#xff0c;提升其达到求知目的的效率。公众号和小程序的迅速发展&#xff0c;又为知识付费提供了技术支持&#xff0c;从而促进了行业的进一步发展。…

UE 虚幻引擎 【DT Subsystem】 插件说明

在虚幻中自带有子系统&#xff0c;可能实现自动实例化。 但是子系统只能在C中继承实现&#xff0c;本插件的目的则是可以直接在蓝图中创建并使用子系统。 官方子系统说明参考&#xff1a; 虚幻引擎编程子系统 | 虚幻引擎5.1文档 (unrealengine.com)https://docs.unrealengine…

Studio 3T 2023.1.1 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端

The professional GUI, IDE and client for MongoDB 请访问原文链接&#xff1a;https://sysin.org/blog/studio-3t-2023/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org Studio 3T&#xff0c;MongoDB 的专业 GUI、IDE 和…

桌面电脑如何快速体验DataEase?

DataEase是一款人人可用的数据可视化分析工具&#xff0c;致力于帮助用户快速分析数据并洞察业务趋势&#xff0c;从而实现业务的改进与优化。但有一些用户提出&#xff0c;目前大部分的部署场景都是将DataEase部署在服务器中&#xff0c;自己只有一台桌面电脑&#xff0c;是不…

初始C++(五):

文章目录一.auto关键字1.1auto关键字用法1.2auto关键字的小细节1.3h获取变量类型二.范围for(语法糖)三.nullptr和NULL一.auto关键字 1.1auto关键字用法 auto这个关键字其实非常简单&#xff0c;用处就是能自动帮你去匹配类型&#xff0c;像下面这段代码&#xff1a; int mai…

Jetpack技术Hilt【实现解耦 】

Hilt是什么&#xff1f; Hilt 是基于 Dagger2 的针对 Android场景定制化 的框架。 这有点像什么&#xff1f; RxAndroid 是 RxJava 的Android平台定制化扩展。Andorid虽然由Java、Kotlin构成&#xff0c;但是它有很多平台的特性&#xff0c;比如它有 Java开发 所不知道的 Cont…

嵌入式开发:AI和Chat GPT改变嵌入式系统的3种方式

嵌入式软件开发是一个已经发展了很多年的领域&#xff0c;它已经见证了许多技术进步。然而&#xff0c;ChatGPT和其他人工智能技术的引入将以前所未有的方式彻底改变该领域。在这篇博文中&#xff0c;我们将探索ChatGPT和AI将改变嵌入式开发的三种方式。方式1 —— CHATGPT/AI自…

Redis之搭建一主多从

搭建redis一主多从的过程 1.在相应位置创建一个文件夹存放redis配置文件 mkdir myredis2.复制redis配置文件到此文件夹中 cp /opt/redis/redis/bin/redis.conf /opt/myredis/redis.conf3.新建三个配置文件 touch redis6379.conf touch redis6380.conf touch redis6381.conf4…

测试开发之Django实战示例 第九章 扩展商店功能

第九章 扩展商店功能在上一章里&#xff0c;为电商站点集成了支付功能&#xff0c;然后可以生成PDF发票发送给用户。在本章&#xff0c;我们将为商店添加优惠码功能。此外&#xff0c;还会学习国际化和本地化的设置和建立一个推荐商品的系统。本章涵盖如下要点&#xff1a;建立…

基于JAVA+SpringBoot+Vue+ElementUI中学化学实验室耗材管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 当前&#xff0c;中学…

【js文字大小自适应】原生js实现文字大小自适应(附完整源码)

目录1、先睹为快2、代码实现第一步、搭建页面第二步、设置样式第三步、JS实现字体自适应3、源码直通车&#xff08;百度云下载&#xff09;【写在前面】之前写过一个大屏的项目&#xff0c;其中里面最头疼的应该是图片&#xff0c;文字&#xff0c;图表&#xff08;echarts&…

分布式事务解决方案——TCC

TCC是Try、Confirm、Cancel三个词语的缩写&#xff0c;TCC要求每个分支事务实现三个操作&#xff1a;预处理Try、确认Confirm、撤销Cancel。1、Try 阶段是做业务检查(一致性)及资源预留(隔离)&#xff0c;此阶段仅是一个初步操作&#xff0c;它和后续的Confirm一起才能真正构成…

Win11系统如何安装Ubuntu20.04(WSL版本)并安装docker

终于还是下定决心去换电脑了……这次采用轻量级的WSL&#xff0c;发现虽然没有占内存的GUI界面&#xff0c;但是编码和阅读文档还是非常nice的 1、首先开启Win11的虚拟机服务 2、下载你期望的Ubuntu服务器&#xff08;这里以20.04为例&#xff09; 安装成功后&#xff0c;发现…

发布的软文如何提高阅读量?

软文文章是一种带有宣传性质的文章&#xff0c;旨在宣传某个产品、品牌或者公司。然而&#xff0c;要想有效地宣传&#xff0c;就必须要让读者真正的阅读并了解软文中的内容。因此&#xff0c;提高软文文章阅读量是非常重要的。下面是一些有助于提高软文文章阅读量的方法&#…

简单记录简单记录

目录1.注册Gmail2.注册ChatGPT3.验证“真人”使用4.开始使用1.注册Gmail 第一步先注册一个谷歌邮箱&#xff0c;你也可以使用微软账号&#xff0c;大部分人选择使用gmail。 申请谷歌邮箱 选择个人用途创建账号即可。 &#x1f4cc;温馨提示&#xff1a; 你直接使用guo内的网…

react路由详解

在学习react路由之前&#xff0c;我们肯定需要安装路由。大家先运行如下命令安装路由。安装之后随我一起探索react路由。 安装 版本v6 npm i react-router-dom -S 页面准备 创建两个文件夹 pages和 router pages文件夹里面放的是页面 router文件夹里面是进行路由配置 路由…

【MySQL】聚合函数和GROUP BY

文章目录1、聚合函数2、GROUP BY3、HAVING4、SELECT的执行过程1、聚合函数 聚合函数作用于一组数据&#xff0c;并对一组数据返回一个值。聚合函数类型&#xff1a;AVG()、SUM()、MAX()、MIN()、COUNT()。不能在 WHERE 子句中使用聚合函数。 SELECT AVG(salary), MAX(salary)…

从0到1一步一步玩转openEuler--14 openEuler DNF(YUM)配置管理

文章目录14.1 DNF配置文件14.1.1 配置main部分14.1.2 配置repository部分14.1.3 显示当前配置14.2 创建本地软件源仓库14.3 添加、启用和禁用软件源14.3.1 添加软件源14.3.2 禁用软件源14.3.3 启用软件源DNF是一款Linux软件包管理工具&#xff0c;用于管理RPM软件包。DNF可以查…

论文笔记: Monocular Depth Estimation: a Review of the 2022 State of the Art

中文标题&#xff1a;单目深度估计&#xff1a;回顾2022年最先进技术 本文对比了物种最近的基于深度学习的单目深度估计方法&#xff1a; GPLDepth(2022)[15]: Global-Local Path Networks for Monocular Depth Estimation with Vertical CutDepthAdabins(2021)[1]: Adabins:…

操作系统:文件系统的实现

一、文件系统结构 磁盘的逻辑单元为块&#xff0c;内存和磁盘之间的I/O传输以块为单位执行。 磁盘的特点 1可以原地重写&#xff0c;可以从磁盘上读一块儿&#xff0c;修改该块&#xff0c;并将它写回到原来的位置可以直接访问磁盘上的任意一块。因此&#xff0c;可以方便地…