Swoole 源码分析之 Http Server 模块

首发原文链接:Swoole 源码分析之 Http Server 模块

Swoole 源码分析之 Http Server 模块

Http 模块的注册初始化#

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

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

Copy
// 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 的所有方法。

Copy
$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 服务启动之前做了一些预先工作。

Copy
// 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_onReceive serv->onReceive = php_swoole_http_server_onReceive; } else { ... // 否则,就是默认回调到 Swoole Server onReceive 的方法 php_swoole_server_onReceive serv->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 进行分别的处理,即回调函数的设置。
并且,最后会真正的执行到 用户自定义对回调函数的 实现。

Copy
// 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_onHandshake if (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 更多的一些了解。并不要求要深刻的掌握,因为,很多的事情都不可能一蹴而就。从自己的实力出发,勿忘初心。

posted @   Yxh_blogs  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
CONTENTS