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://www.mzph.cn/news/788545.shtml

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

相关文章

gin源码分析(1)--初始化中间件,路由组与路由树

目标 关于gin.Default(),gin.New(),gin.Use()group与子group之间的关系,多group与middleware之间关系中间件的类型,全局,group,get,不同类型的中间件什么时候执行。中间件 next 和abort行为如何…

Go-Gin中优雅的实现参数校验,自定义错误消息提示

问题描述 在参数校验的时候我们一般会基于"github.com/go-playground/validator/v10"这个库给结构体加标签实现校验参数,当参数校验错误的时候,他的提示一般是英文的,怎么自定义参数错误提示呢?跟着我一步步来 注册校…

OpenAI 宣布, ChatGPT 网页端无需注册就能立即使用(2024年4月1日)

今天,OpenAI宣布,为了让更多人轻松体验人工智能的强大功能,现在无需注册账户即可立即使用 ChatGPT。这一变化是他们使命的核心部分,即让像 ChatGPT 这样的工具广泛可用,让世界各地的人们都能享受到 AI 带来的好处。 网…

PostgreSQL的学习心得和知识总结(一百三十五)|深入理解PostgreSQL数据库之查找 PostgreSQL C 代码中的内存泄漏

目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《PostgreSQL数据库内核分析》 2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》 3、PostgreSQL数据库仓库…

【苍穹外卖】SkyApplication类启动报错

报的这个错 The PoM for com.sky:sky-common:jar:1.0-SNAPSHoT is missing, no dependency information available Maven里重新install一下就好

01-​JVM学习记录-类加载器

一、类加载器子系统 1. 作用-运输工具(快递员) 负责从文件系统或者网络中加载Class文件(DNA元数据模板),Class文件开头有特定标识,魔术,咖啡杯壁(class文件存于本地硬盘&#xff0c…

Java 设计模式系列:备忘录模式

简介 备忘录模式是一种软件设计模式,用于在不破坏封闭的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定…

微信小程序开发学习笔记——4.8【小案例】初识wx.request获取网络请求并渲染至页面

>>跟着b站up主“咸虾米_”学习微信小程序开发中,把学习记录存到这方便后续查找。 课程连接:4.8.【小案例】初识wx.request获取网络请求并渲染至页面_哔哩哔哩_bilibili up主提供的网络请求常用接口: 随机猫咪,用来获取一些…

【Kotlin】委托模式

1 委托模式简介 委托模式的类图结构如下。 对应的 Kotlin 代码如下。 fun main() {var baseImpl BaseImpl()var baseWrapper BaseWrapper(baseImpl)baseWrapper.myFun1() // 打印: BaseImpl, myFun1baseWrapper.myFun2() // 打印: BaseImpl, myFun2 }interface Base {fun my…

非关系型数据库(缓存数据库)redis的基础认知与安装

目录 一.关系型数据库和非关系型数据库 关系型数据库 非关系型数据库 关系数据库与非关系型数据库的区别 ①非关系数据 关系型数据库 非关系型数据库产生背景 数据存储流向 非关系型数据库 关系数据库 二.redis的简介 1.概念 2.Redis 具有以下几个优点: 3.Redi…

测斜仪在边坡安全监测中的重要作用

边坡作为土木工程和地质工程领域中常见的结构形式,其稳定性直接关系到工程安全以及人民生命财产的安全。因此,对边坡进行精确、及时的监测是至关重要的。在众多边坡监测仪器中,测斜仪以其独特的优势在边坡安全监测中发挥着重要的作用。 测斜仪…

uniapp:小程序腾讯地图程序文件qqmap-wx-jssdk.js 文件一直找不到无法导入

先看问题: 在使用腾讯地图api时无法导入到qqmap-wx-jssdk.js文件 解决方法:1、打开qqmap-wx-jssdk.js最后一行 然后导入:这里是我的路径位置,可以根据自己的路径位置进行更改导入 最后在生命周期函数中输出: 运行效果…

vivado 高级编程功能1

适用于 7 系列、 UltraScale 和 UltraScale FPGA 和 MPSoC 的回读和验证 为 7 系列器件生成已加密文件和已经过身份验证的文件 注释 : 如需获取其它信息 , 请参阅《使用加密确保 7 系列 FPGA 比特流的安全》 ( XAPP1239 ) 。 要生成加密比特流…

设计模式之代理模式解析(下)

4)远程代理介绍 远程代理(Remote Proxy) 使客户端程序可以访问在远程主机上的对象,远程代理对象承担了大部分的网络通信工作,并负责对远程业务方法的调用。 5)虚拟代理介绍 1.概述 虚拟代理(Virtual Proxy) 对于一些占用系统资…

零基础入门多媒体音频(7)-AAOS audio

概览 Android Automotive OS (AAOS) 是基于核心的 Android 音频堆栈打造,以支持用作车辆信息娱乐系统。AAOS 负责实现信息娱乐声音(即媒体、导航和通讯),但不直接负责具有严格可用性和时间要求的铃声和警告。 虽然 AAOS 提供了信号…

路由器拨号失败解决方法

目录 一、遇到问题 二、测试 三、解决方法 (一)路由器先单插wan口设置 (二)mac地址替换 (三)更改路由器DNS 一、遇到问题 1 .在光猫使用桥接模式,由路由器进行拨号的时候,出现…

【C语言】——指针七:数组和指针试题解析

【C语言】——指针七: 前言一、 s i z e o f sizeof sizeof 与 s t r l e n strlen strlen 的对比1.1、 s i z e o f sizeof sizeof1.2、 s t r l e n strlen strlen1.3、 s i z e o f sizeof sizeof 和 s t r l e n strlen strlen 对比 二、数组和指针笔试题解析…

算法打卡day32|贪心算法篇06|Leetcode 738.单调递增的数字、968.监控二叉树

算法题 Leetcode 738.单调递增的数字 题目链接:738.单调递增的数字 大佬视频讲解:单调递增的数字视频讲解 个人思路 这个题目就是从例子中找规律,例如 332,从后往前遍历,32不是单调递增将2变为9,3减1,变成了329&…

Marin说PCB之电源完整性之电源网络的PDN仿真CST---01

最近朋友圈最火的消息我感觉是除了开封的王婆外莫过于是小米SU7汽车发布这件事情了,小编我也是一位资深的米粉,我在上个月28号的时候守在电脑前直播看小米SU7汽车的发布会,其中雷总演讲的一段话很打动我:不甘于平庸,还…

微信小程序-文字转语音(播放及暂停)

1、使用微信小程序的同声传译功能 小程序平台-设置-第三方设置-插件管理-新增同声传译插件 小程序app.json文件配置 "plugins": {"WechatSI": {"version": "0.3.5","provider": "wx069ba97219f66d99"}},小程序中…