经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
详解PHP实现HTTP服务器过程
来源:jb51  时间:2023/2/17 9:59:09  对本文有异议

PHP并非不能实现HTTP服务,一般来讲,这叫网络编程或Socket编程。在学习到其他语言的这部分的时候,一般的思路就是如何监听TCP实现一个服务器,并处理HTTP协议。

PHP也可以这样做,同时一般伴随着高性能这样的关键字出现。

原生Socket编程

我们可以通过PHP的Socket函数,很简单的实现出HTTP服务。

  1. function run()
  2. {
  3. //创建服务端的socket套接流,net协议为IPv4,protocol协议为TCP
  4. $socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
  5. /*绑定接收的套接流主机和端口,与客户端相对应*/
  6. if(socket_bind($socket,"0.0.0.0", 9502) == false){
  7. echo 'server bind fail:'.socket_strerror(socket_last_error());exit();
  8. }
  9. //监听套接流
  10. if(socket_listen($socket,4)==false){
  11. echo 'server listen fail:'.socket_strerror(socket_last_error());exit();
  12. }
  13. //非阻塞
  14. socket_set_nonblock($socket);
  15. call_user_func('onAccept',$socket);
  16. }
  17. run();

然后通过Socket处理收到的数据以及作出响应:

  1. function onMessage($connection)
  2. {
  3. //拼装返回的html内容
  4. $content = '<html><title>hello,world</title><body>hello,world,http</body></html>';
  5. //拼装头信息
  6. $header = '';
  7. $header .= "HTTP/1.1 200 OK\r\n";
  8. $header .= "Date: ".gmdate('D, d M Y H:i:s T')."\r\n";
  9. $header .= "Content-Type: text/html;charset=utf-8\r\n";
  10. $header .= "Content-Length: ".strlen($content)."\r\n\r\n";//必须2个\r\n表示头部信息结束
  11. $header .= $content;
  12. socket_write($connection,$header,strlen($header));
  13. }
  14. function onAccept($socket)
  15. {
  16. //接收客户端传递过来的信息
  17. while(true)
  18. {
  19. $accept_resource = socket_accept($socket);
  20. if($accept_resource !== false)
  21. {
  22. $string = socket_read($accept_resource,1024);
  23. echo 'server receive is :'.$string.PHP_EOL;
  24. if($string != false)
  25. {
  26. call_user_func('onMessage',$accept_resource);
  27. }
  28. }
  29. }
  30. }

流行项目

实际上,PHP有很多在项目都在实现HTTP服务器,而且他们一般也都宣称是高性能的。

Workerman系

Workerman是一款纯PHP开发的开源高性能的PHP 应用容器。几乎能够实现任何类型的网络编程,并且内置了一个HTTP协议。

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

Workerman的官方在21年出品了Webman,一个基于Workerman实现的高性能HTTP服务框架。替代传统PHP-FPM架构,提供高性能的HTTP服务。可以用来开发网站、接口、微服务。

Webman实际上是一个开发框架,项目的目录结构都已经设定好了,按照文档开发就行,最后只要通过命令就能运行起来。

php start.php start

Webman支持是一个MVC框架,支持命名空间自动加载,所以代码像这样:

  1. <?php
  2. namespace app\controller;
  3. use support\Request;
  4. class UserController
  5. {
  6. public function hello(Request $request)
  7. {
  8. $default_name = 'webman';
  9. // 从get请求里获得name参数,如果没有传递name参数则返回$default_name
  10. $name = $request->get('name', $default_name);
  11. // 向浏览器返回字符串
  12. return response('hello ' . $name);
  13. }
  14. }

除了高性能等特点,他的上手难度很低,并且风格与现代的MVC风格一致,支持PSR标准,代码精简高效。如果你是ThinkPHP的开发者,你会发现很容易上手Webman。

Swoole系

说道高性能HTTP服务,总是绕不开swoole的,他也是国内最早火热起来的PHP高性能解决方案。

使用swoole实现HTTP服务的代码也很简单:

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

swoole实际上是一个PHP的扩展,近几年基于他发展起了很多的高性能框架,比如easyswoole、Hyperf、Swoft、MixPHP等等。它们都基于Swoole实现框架,可以很容易的创建完整度很成熟的系统。

ReactPHP系

ReactPHP 是用于 PHP 事件驱动编程的底层库。也可以用来实现各类网络编程,包括HTTP服务。用它实现HTTP服务也很简单:

  1. require __DIR__ . '/vendor/autoload.php';
  2. $http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
  3. return React\Http\Message\Response::plaintext(
  4. "Hello World!\n"
  5. );
  6. });
  7. $socket = new React\Socket\SocketServer('127.0.0.1:8080');
  8. $http->listen($socket);
  9. 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服务。

  1. use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
  2. use Amp\Http\Server\SocketHttpServer;
  3. use Amp\Http\Server\Request;
  4. use Amp\Http\Server\Response;
  5. use Amp\Http\Status;
  6. use Amp\Socket\Server;
  7. use Psr\Log\NullLogger;
  8. // Run this script, then visit http://localhost:1337/ in your browser.
  9. Amp\Loop::run(function () {
  10. $sockets = [
  11. Server::listen("0.0.0.0:1337"),
  12. Server::listen("[::]:1337"),
  13. ];
  14. $server = new SocketHttpServer($sockets, new ClosureRequestHandler(function (Request $request) {
  15. return new Response(Status::OK, [
  16. "content-type" => "text/plain; charset=utf-8"
  17. ], "Hello, World!");
  18. }), new NullLogger);
  19. yield $server->start();
  20. // Stop the server gracefully when SIGINT is received.
  21. // This is technically optional, but it is best to call Server::stop().
  22. Amp\Loop::onSignal(SIGINT, function (string $watcherId) use ($server) {
  23. Amp\Loop::cancel($watcherId);
  24. yield $server->stop();
  25. });
  26. });

AMPHP也实现了很多有趣的项目,比如Mysql的客户端,能够实现连接池等特性。

swow

swow是一个基于协程的跨平台并发I/O引擎,关注并发IO。

官方给出的HTTP例子代码行数比较多,主要是展示了HTTP请求支持的每个阶段的操作方法,代码也是很简洁的。

  1. declare(strict_types=1);
  2. use Swow\Buffer;
  3. use Swow\Coroutine;
  4. use Swow\Http\Parser;
  5. use Swow\Http\ParserException;
  6. use Swow\Socket;
  7. use Swow\SocketException;
  8. $host = getenv('SERVER_HOST') ?: '127.0.0.1';
  9. $port = (int) (getenv('SERVER_PORT') ?: 9764);
  10. $backlog = (int) (getenv('SERVER_BACKLOG') ?: 8192);
  11. $multi = (bool) (getenv('SERVER_MULTI') ?: false);
  12. $bindFlag = Socket::BIND_FLAG_NONE;
  13. $server = new Socket(Socket::TYPE_TCP);
  14. if ($multi) {
  15. $server->setTcpAcceptBalance(true);
  16. $bindFlag |= Socket::BIND_FLAG_REUSEPORT;
  17. }
  18. $server->bind($host, $port, $bindFlag)->listen($backlog);
  19. while (true) {
  20. try {
  21. $connection = $server->accept();
  22. } catch (SocketException $exception) {
  23. break;
  24. }
  25. Coroutine::run(static function () use ($connection): void {
  26. $buffer = new Buffer(Buffer::COMMON_SIZE);
  27. $parser = (new Parser())->setType(Parser::TYPE_REQUEST)->setEvents(Parser::EVENT_BODY);
  28. $parsedOffset = 0;
  29. $body = null;
  30. try {
  31. while (true) {
  32. $length = $connection->recv($buffer, $buffer->getLength());
  33. if ($length === 0) {
  34. break;
  35. }
  36. while (true) {
  37. $parsedOffset += $parser->execute($buffer, $parsedOffset);
  38. if ($parser->getEvent() === $parser::EVENT_NONE) {
  39. $buffer->truncateFrom($parsedOffset);
  40. $parsedOffset = 0;
  41. break; /* goto recv more data */
  42. }
  43. if ($parser->getEvent() === Parser::EVENT_BODY) {
  44. $body ??= new Buffer(Buffer::COMMON_SIZE);
  45. $body->write(0, $buffer, $parser->getDataOffset(), $parser->getDataLength());
  46. }
  47. if ($parser->isCompleted()) {
  48. $response = sprintf(
  49. "HTTP/1.1 200 OK\r\n" .
  50. "Connection: %s\r\n" .
  51. "Content-Length: %d\r\n\r\n" .
  52. '%s',
  53. $parser->shouldKeepAlive() ? 'Keep-Alive' : 'Closed',
  54. $body ? $body->getLength() : 0,
  55. $body ?: ''
  56. );
  57. $connection->send($response);
  58. $body?->clear();
  59. break; /* goto recv more data */
  60. }
  61. }
  62. if (!$parser->shouldKeepAlive()) {
  63. break;
  64. }
  65. }
  66. } catch (SocketException $exception) {
  67. echo "No.{$connection->getFd()} goaway! {$exception->getMessage()}" . PHP_EOL;
  68. } catch (ParserException $exception) {
  69. echo "No.{$connection->getFd()} parse error! {$exception->getMessage()}" . PHP_EOL;
  70. }
  71. $connection->close();
  72. });
  73. }

总结

以上是一些非常流行的PHP框架和项目,但还有其他很多实现了高性能HTTP服务的项目。这里不多做介绍了。虽然我们谈到PHP的时候,很少谈到网络编程,甚至在入门教程中根本就没有网络编程这节课。但是使用PHP做网络编程的各项应用已经很火热了。

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

到此这篇关于详解PHP实现HTTP服务器过程的文章就介绍到这了,更多相关PHP HTTP服务器内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号