03 | Swoole 源码分析之 Http Server 模块

首发原文链接:Swoole 源码分析之 Http Server 模块
大家好,我是码农先森。

Http 模块的注册初始化

这次我们分析的就是 Swoole 官网的这段代码,看似简单,实则不简单。

Swoole 源码文件 swoole_http_server.c 中有这样一个函数 php_swoole_http_server_minit
这个函数是专门用来注册及初始化 Http Server 模块的,如果不预先注册,那么在 PHP 编程 中无法使用的。

// swoole-src/ext-src/swoole_http_server.c:172
void php_swoole_http_server_minit(int module_number) {// 定义 Swoole\Http\Server 为 PHP 中的类名// 并且 swoole_http_serve 继承了 swoole_server 即可以使用 `swoole_server` 的所有方法SW_INIT_CLASS_ENTRY_EX(swoole_http_server, "Swoole\\Http\\Server", nullptr, nullptr, swoole_server);// 这里设置为不可序列化,也就是说这个类能被序列化SW_SET_CLASS_NOT_SERIALIZABLE(swoole_http_server);// 这里设置为不可克隆,也就是说这个类的对象不能被复制SW_SET_CLASS_CLONEABLE(swoole_http_server, sw_zend_class_clone_deny);// 这里设置为不可删除属性,也就是这个类的属性不能被删除SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_http_server, sw_zend_class_unset_property_deny);
}

从上面的这段初始化代码可以看出, swoole_http_server 继承了 swoole_server。因此,可以使用 swoole_server 的所有方法。

$http = new Swoole\Http\Server('127.0.0.1', 9501);
$http->on('start', function ($server) {});
$http->on('request', function ($request, $response) {});

这里的 new Swoole\Http\Server('127.0.0.1', 9501)$http->on('start', function ($server) {}$http->on('request', function ($request, $response) {});
在实际的调用中都是在 swoole_server 完成的,因此这里不会再过多的介绍了。可以看我之前的文章 Swoole 源码分析之 TCP Server 模块 这里都介绍了关于 构造函数、回调函数的 实现方式。

下面我们会着重介绍 $http->start() 这个函数,针对 swoole_http_server 做了一些特殊的实现。

$http->start() 的实现

话不多说,先上一张整体的实现图。$http->start() 这个方法的实现,在 Swoole 源码中最直接对应的就是 static PHP_METHOD(swoole_server, start) 这个函数。

那么刚刚说过,针对 swoole_http_server 做了一些特殊的实现。那么在哪里做的特殊处理呢?
我们来分析这个方法 on_before_start(),它是在真正的 start 服务启动之前做了一些预先工作。

// swoole-src/ext-src/swoole_server.cc:779
void ServerObject::on_before_start() {...bool find_http_port = false;// 检查是否是 redis 服务if (is_redis_server()) {...serv->onReceive = php_swoole_redis_server_onReceive;// 检查是否是 http 服务} else if (is_http_server()) {// 检查是否是 websocket 服务if (is_websocket_server()) {if (!isset_callback(primary_port, SW_SERVER_CB_onMessage)) {php_swoole_fatal_error(E_ERROR, "require onMessage callback");return;}} else if (!isset_callback(primary_port, SW_SERVER_CB_onRequest)) {php_swoole_fatal_error(E_ERROR, "require onRequest callback");return;}....primary_port->open_http_protocol = 1;primary_port->open_http2_protocol = !!(protocol_flag & SW_HTTP2_PROTOCOL);primary_port->open_websocket_protocol = !!(protocol_flag & SW_WEBSOCKET_PROTOCOL);find_http_port = true;// 设置 Swoole Server 真正的 onReceive 回调是 php_swoole_http_server_onReceiveserv->onReceive = php_swoole_http_server_onReceive;} else {...// 否则,就是默认回调到 Swoole Server onReceive 的方法 php_swoole_server_onReceiveserv->onReceive = php_swoole_server_onReceive;}...if (find_http_port) {serv->onReceive = php_swoole_http_server_onReceive;}...
}

on_before_start 这个方法中,可以看到不仅是对 http_server 做了处理,针对 redis_server 也是如此。
我们最开始提到的 $http->on('request', function ($request, $response) {}); 其中针对被实现的方法是在 php_swoole_http_server_onReceive 中。
接下来,我们揭开 php_swoole_http_server_onReceive 函数的神秘面纱。

php_swoole_http_server_onReceive 函数的实现

这个函数里面会对 http serverwebsocket server 进行分别的处理,即回调函数的设置。
并且,最后会真正的执行到 用户自定义对回调函数的 实现。

// swoole-src/ext-src/swoole_http_server.cc:51
int php_swoole_http_server_onReceive(Server *serv, RecvData *req) {// 获取到对于的连接对象Connection *conn = serv->get_connection_verify_no_ssl(session_id);...// 如果是 websocket 连接,则进行对应的处理if (conn->websocket_status == WebSocket::STATUS_ACTIVE) {return swoole_websocket_onMessage(serv, req);}// 如果是 http2 连接,则进行对应的处理if (conn->http2_stream) {return swoole_http2_server_onReceive(serv, conn, req);}...// 开始注册对应的回调函数do {zend_fcall_info_cache *fci_cache = nullptr;// 如果是 websocket 连接,则这是对应的回调函数 SW_SERVER_CB_onHandshakeif (conn->websocket_status == WebSocket::STATUS_CONNECTION) {fci_cache = php_swoole_server_get_fci_cache(serv, server_fd, SW_SERVER_CB_onHandshake);if (fci_cache == nullptr) {swoole_websocket_onHandshake(serv, port, ctx);goto _dtor_and_return;} else {conn->websocket_status = WebSocket::STATUS_HANDSHAKE;ctx->upgrade = 1;}// 否则是 Http 连接,则这是对应的回调函数 SW_SERVER_CB_onRequest} else {fci_cache = php_swoole_server_get_fci_cache(serv, server_fd, SW_SERVER_CB_onRequest);if (fci_cache == nullptr) {swoole_websocket_onRequest(ctx);goto _dtor_and_return;}}ctx->private_data_2 = fci_cache;if (ctx->onBeforeRequest && !ctx->onBeforeRequest(ctx)) {return SW_OK;}// 对 request 请求进行回调处理http_server_process_request(serv, fci_cache, ctx);} while (0);...return SW_OK;
}// swoole-src/ext-src/swoole_http_server.cc:51
static void http_server_process_request(Server *serv, zend_fcall_info_cache *fci_cache, HttpContext *ctx) {zval args[2];// request 回调函数中的 request 参数args[0] = *ctx->request.zobject;// request 回调函数中的 response 参数args[1] = *ctx->response.zobject;// 执行真正的调用,这里将会直接执行 用户自定义对回调函数的 实现if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, nullptr, serv->is_enable_coroutine()))) {...}
}

其中 fci_cache 这个变量代表的就是 function ($request, $response) {} 这个函数,args[0] 代表的是 $requestargs[1] 代表的是 $response
对于 Http Server 模块来说,最重要的就是这个回调方法了,因为所有的业务逻辑都是在这里进行实现的。

总结

想要了解到 Http Server 的全貌,其实只要把那张整体的实现图看懂就足以了。但是,如果想要有足够的深度,那么就还需要深入 Swoole 的源代码中,就着源码自行分析一遍。同时,也希望这一次的分析,能够给大家带来对 Swoole 更多的一些了解。并不要求要深刻的掌握,因为,很多的事情都不可能一蹴而就。从自己的实力出发,勿忘初心。

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

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

相关文章

【Redis】数据类型、事务执行、内存淘汰策略

目录 数据类型 Redis事务执行步骤 步骤: redis内存淘汰策略 设置内存淘汰策略 1.设置配置文件 2.通过命令设置 数据类型 官网解释 Understand Redis data types | Redis 首先,Redis 的所有键都是字符串,常用的数据类型有 5 种:Strin…

docker-compose mysql

使用docker-compose 部署 MySQL(所有版本通用) 一、拉取MySQL镜像 我这里使用的是MySQL8.0.18,可以自行选择需要的版本。 docker pull mysql:8.0.18二、创建挂载目录 mkdir -p /data/mysql8/log mkdir -p /data/mysql8/data mkdir -p /dat…

enscan自动化主域名信息收集

enscan下载 Releases wgpsec/ENScan_GO (github.com) 能查的分类 实操: 首先打开linux 的虚拟机、 然后把下面这个粘贴到虚拟机中 解压后打开命令行 初始化 ./enscan-0.0.16-linux-amd64 -v 命令参数如下 oppo信息收集 运行下面代码时 先去配置文件把coo…

47 vue 常见的几种模型视图不同步的问题

前言 这里主要是来看一下 关于 vue 中的一些场景下面 可能会出现 模型和视图 不同步更新的情况 然后 这种情况主要是 vue 中的对象 属性没有响应式的 setter, getter 然后 我们这里就来看一下 大多数的情况下的一个场景, 和一些处理方式 当然 处理方式主要是基于 Vue.set, …

HTML CSS 简单小实例

一、登录注册页面 1.需求文档内容如下: 1.登录 用户名: 密码: 注册按钮跳转注册界面 忘记密码按钮跳转忘记密码界面 登录按钮跳转个人页面 2.注册 用户名:3-8字符(字母开头) 密码:6-12字符&…

Elasticsearch 和 Kibana 8.13:简化 kNN 和改进查询并行化

作者:Gilad Gal, Tyler Perkins, Srikanth Manvi, Aris Papadopoulos, Trevor Blackford 在 8.13 版本中,Elastic 引入了向量搜索的重大增强,并将 Cohere 嵌入集成到其统一 inference API 中。这些更新简化了将大型语言模型(LLM&a…

2024年北京事业单位报名照片要求,注意格式

2024年北京事业单位报名照片要求,注意格式

nacos的各种类型的配置文件 yml 、json、 Properties、 text 等文件类型 发生变化怎么热更新,实现实时监听nacos配置文件变化

本文用的是 Nacos作为配置中心注册监听器方法 实现热更新 nacos 配置文件 从而不用重启项目 依赖、工具类 这边就不写了 因为项目用的是 Json 类型的配置文件 所以下文 主要是对json文件进行实现 别的文件大同小异 先说扯淡的东西 在nacos 的配置文件中 dataId 这两种声明 是…

系统分析师-软件开发模型总结

前言 软件工程模型也称软件开发模型。它是指软件开发全部过程、活动和任务的结构框架,通过该模型能清晰、直观地表达软件开发全过程,明确地规定要完成的主要活动和任务,它奠定了软件项目工作的基础 一、瀑布模型(Waterfall Model…

FPGA时钟资源详解(3)——全局时钟资源

FPGA时钟系列文章总览:FPGA原理与结构(14)——时钟资源https://ztzhang.blog.csdn.net/article/details/132307564 一、概述 全局时钟是 FPGA 中的一种专用互连网络,旨在将时钟信号分配到 FPGA 内各种资源的时钟输入处。这种设计…

【目标检测】YOLOv5 网络结构,bottleneckCSP 与 C3 模块图解

文章目录 Focus 模块Csp 模块BottleneckCspC3CSP1_X 与 CSP_2XYOLOv4 的 CSP_X SSP 与 SSPF YOLOv5 作为 YOLO 家族的第五个版本,本身也演进了几个子版本,现在网上的资料都没有标注具体是哪个子版本的,导致不同文章之间各种混乱,像…

【FedCoin: A Peer-to-Peer Payment System for Federated Learning】

在这篇论文中,我们提出了FedCoin,一个基于区块链的点对点支付系统,专为联邦学习设计,以实现基于Shapley值的实际利润分配。在FedCoin系统中,区块链共识实体负责计算SV,并且新的区块是基于“Shapley证明”&a…

如何通过vscode连接到wsl

下载wsl扩展 远程连接模式

天锐绿盾 || 公司文件数据加密系统,资料防泄密软件,国内专业数据安全系统——自动智能无感透明加密、防泄密管理系统

#天锐绿盾# 天锐绿盾是一款专为中国企业设计的数据防泄密系统,旨在为企业提供全方位的数据安全解决方案,特别关注对敏感信息和核心技术资料的保护。 www.drhchina.com PC地址: https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-9…

Oracle存数字精度问题number、binary_double、binary_float类型

--表1 score是number(10,5)类型 create table TEST1 (score number(10,5) ); --表2 score是binary_double类型 create table TEST2 (score binary_double ); --表3 score是binary_float类型 create table TEST3 (score binary_float );实验一:分别往三张表插入 小数…

苹果应用商店上架工具的最新趋势与未来发展展望

摘要 移动应用app上架是开发者关注的重要环节,但常常会面临审核不通过等问题。为帮助开发者顺利完成上架工作,各种辅助工具应运而生。本文探讨移动应用app上架原理、常见辅助工具功能及其作用,最终指出合理使用工具的重要性。 引言 移动应…

衢州常山县行政服务中心 | 55寸1x5弧形显示屏

项目产品:55寸OLED柔性屏 项目时间:2023年3月 项目地点:衢州常山县行政服务中心办公室 近日,衢州常山县行政服务中心成功完成了其办公室内的55寸1x5弧形显示屏的安装与调试工作。此次项目采用了先进的55寸OLED柔性屏,…

C++王牌结构hash:哈希表闭散列的实现与应用

一、哈希概念 顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素 时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(log n),搜索的效率…

selenium实战之爬取虎牙直播列表页

文章目录 声明实现流程给你主播列表页面分析登录遮罩层处理解析直播列表的数据分页处理 完整的代码 声明 前面有了 selenium的基础,这里就拿虎牙直播页面来做一个实战测试,这是作为学习,测试使用,并不用作为商业用途,不…

【话题】AI大模型学习:理论、技术与应用探索

大家好,我是全栈小5,欢迎阅读小5的系列文章,这是《话题》系列文章 目录 背景1. AI大模型学习的基础理论1.1 机器学习1.2 深度学习 2. AI大模型学习的技术要点2.1 模型结构设计2.2 算法优化2.3 大规模数据处理 3. AI大模型学习的应用场景3.1 自…