php 代理服务器-深入理解PHP与WEB服务器交互

2023-08-30 0 10,051 百度已收录

1、WEB服务器调用PHP套接字

以Apache服务器为例,我们看看服务器是如何启动PHP并调用PHP中的技术的。 Apache服务器启动并运行PHP时,通常是通过mod_php7模块进行集成(如果是php5.apache2handler/mod_php7.c):

AP_MODULE_DECLARE_DATA module php7_module = {
    STANDARD20_MODULE_STUFF,/* 宏,包括版本,版本,模块索引,模块名,下个模块指针等信息 */
    create_php_config,      /* create per-directory config structure */
    merge_php_config,       /* merge per-directory config structures */
    NULL,                   /* create per-server config structure */
    NULL,                   /* merge per-server config structures */
    php_dir_cmds,           /* 模块定义的所有指令 */
    php_ap2_register_hook   /* register hooks */

};

当Apache需要调用PHP中的方法时,只需通过mod_php7模块将请求传递给PHP即可。 PHP层处理完后,将数据返回给Apache,整个过程就结束了(补充一下:Apache服务器启动PHP时,虽然有两种加载方式,一种是静态加载,一种是动态加载)刚刚讨论的mod_php5模块加载方式可以理解为静态加载,也就是说需要重启Apache服务器才能加载PHP;

动态加载不需要重启服务器。 只需要通过发送信号的方式加载PHP固定模块到服务器即可达到PHP启动的目的。 并且在动态加载之前,需要将加载的模块编译成动态链接库,然后在服务器的配置文件中进行配置)。 PHP中Apache的模型结构已经给出。 下面给出Apache服务器中对应的模块结构,如下(源码在Apache中,下同):

struct module_struct {
    int version;
    int minor_version;
    int module_index;
    const char *name;
    void *dynamic_load_handle;
    struct module_struct *next;
    unsigned long magic;
    void (*rewrite_args) (process_rec *process);
    void *(*create_dir_config) (apr_pool_t *p, char *dir);
    void *(*merge_dir_config) (apr_pool_t *p, void *base_conf, void *new_conf);
    void *(*create_server_config) (apr_pool_t *p, server_rec *s);
    void *(*merge_server_config) (apr_pool_t *p, void *base_conf, void *new_conf);
    const command_rec *cmds;
    void (*register_hooks) (apr_pool_t *p);

}

php 代理服务器-深入理解PHP与WEB服务器交互

可以看出,php7_module和module_struct还是有很大不同的,但是如果你看到宏php7_module.STANDARD20_MODULE_STUFF的定义方法,你可能也会觉得这两个结构体很相似,虽然这个宏定义了module_struct中的前8个参数,定义如下:

#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, 
    MODULE_MAGIC_NUMBER_MINOR, 
    -1
    __FILE__
    NULL
    NULL
    MODULE_MAGIC_COOKIE, 
    NULL /* rewrite args spot */

之后,php7_module.php_dir_cmds定义了该模块的所有指令集。 具体定义内容如下(代码路径为php/sapi/apache2handler/apache_config.c):

const command_rec php_dir_cmds[] =
{
    AP_INIT_TAKE2("php_value", php_apache_value_handler, NULL, OR_OPTIONS, "PHP Value Modifier"),
    AP_INIT_TAKE2("php_flag", php_apache_flag_handler, NULL, OR_OPTIONS, "PHP Flag Modifier"),
    AP_INIT_TAKE2("php_admin_value", php_apache_admin_value_handler, NULL, ACCESS_CONF|RSRC_CONF, "PHP Value Modifier (Admin)
    "
),
    AP_INIT_TAKE2("php_admin_flag", php_apache_admin_flag_handler, NULL, ACCESS_CONF|RSRC_CONF, "PHP Flag Modifier (Admin)"),
    AP_INIT_TAKE1("PHPINIDir", php_apache_phpini_set, NULL, RSRC_CONF, "Directory containing the php.ini file"),
    {NULL}

};

php 代理服务器-深入理解PHP与WEB服务器交互

也就是说,PHP层只向Apache提供了以上5条指令。 各指令的实现源码也在apache_config.c文件中。 最终留下了php7_module.php_ap2_register_hook,其定义如下(代码路径为php/sapi/apache2handler/mod_php7.c):

void php_ap2_register_hook(apr_pool_t *p)
{
    ap_hook_pre_config(php_pre_config, NULLNULL, APR_HOOK_MIDDLE);
    ap_hook_post_config(php_apache_server_startup, NULLNULL, APR_HOOK_MIDDLE);
    ap_hook_handler(php_handler, NULLNULL, APR_HOOK_MIDDLE);
#ifdef ZEND_SIGNALS
    ap_hook_child_init(zend_signal_init, NULLNULL, APR_HOOK_MIDDLE);
#endif
    ap_hook_child_init(php_apache_child_init, NULLNULL, APR_HOOK_MIDDLE);
}

php7_module.php_ap2_register_hook函数包含4个hook以及相应的处理函数。 pre_config、pre_config、post_config 和 child_init 是启动钩子,在服务器启动时调用。 handler hook是一个request hook,当服务器请求时会调用它。 通过这个钩子,你可以通过Apache服务器启动PHP。

到这里,相信你已经知道WEB服务器是如何启动PHP并调用PHP中的方法了。 接下来我就讲讲PHP如何调用WEB服务器socket。

2. PHP调用WEB服务器socket

在讲这个问题之前,我们需要先了解一下SAPI是什么。 虽然SAPI是与服务器具体层的通用协议,但它很容易理解。 当PHP需要调用服务器中的方法时,比如清除缓存、消除缓存等,实现方法都是在服务器中实现的,PHP层根本不知道。 在服务器端如何调用这个方法呢? 我应该怎么办? 这时候双方就需要达成一致,然后服务器向PHP提供一组约定好的socket。 我们将这种与服务器具体层的通用协议称为 SAPI 套接字。

问题是,对于服务器Apachephp 代理服务器,我们可以提供一套SAPI,而如果上次还有其他服务器或者其他“第三方php 代理服务器,我们是否也需要为他们提供一套单独的SAPI? ?

我们聪明的PHP开发者一定想到了这一点,那就是为所有的“第三方”提供一套通用的SAPI套接字,你可能会问,如果新的“第三方”需要套接字,那你的通用SAPI有什么用呢?我应该做什么? 我的理解是给PHP的通用SAPI套接字添加新的功能。 这只是我个人的意见。 通用SAPI结构如下(源码路径:php/main/SAPI.h):

php 代理服务器-深入理解PHP与WEB服务器交互

struct _sapi_module_struct {
    char *name;         // 名字
    char *pretty_name;  // 更好理解的名字
    int (*startup)(struct _sapi_module_struct *sapi_module);    // 启动函数
    int (*shutdown)(struct _sapi_module_struct *sapi_module);   // 关闭函数
    int (*activate)(TSRMLS_D);           // 激活
    int (*deactivate)(TSRMLS_D);         // 停用
    void (*flush)(void *server_context); // flush
    char *(*read_cookies)(TSRMLS_D);     //read Cookies
    //...

};

这个结构体中有很多变量,就不一一列举了。 我们简单解释一下上面的变量:startup函数在SAPI初始化时会被调用,shutdown函数用于释放SAPI的数据结构和显存,read_cookie用于SAPI中。 激活时被调用,然后将这个函数得到的value参数交给SG(request_info).cookie_data。

那么对于PHP提供的通用SAPI,Apache服务器如何定制自己的socket呢? 具体结构如下(源码路径为php/sapi/apache2handler/sapi_apache2.c):

static sapi_module_struct apache2_sapi_module = {
    "apache2handler",
    "Apache 2.0 Handler",

    php_apache2_startup,            /* startup */
    php_module_shutdown_wrapper,    /* shutdown */

    NULL,                           /* activate */
    NULL,                           /* deactivate */

    php_apache_sapi_ub_write,       /* unbuffered write */
    php_apache_sapi_flush,          /* flush */
    php_apache_sapi_get_stat,       /* get uid */
    php_apache_sapi_getenv,         /* getenv */

    php_error,                      /* error handler */

    php_apache_sapi_header_handler, /* header handler */
    php_apache_sapi_send_headers,   /* send headers handler */
    NULL,                           /* send header handler */

    php_apache_sapi_read_post,      /* read POST data */
    php_apache_sapi_read_cookies,   /* read Cookies */

    php_apache_sapi_register_variables,
    php_apache_sapi_log_message,        /* Log message */
    php_apache_sapi_get_request_time,   /* Request Time */
    NULL,                               /* Child Terminate */

    STANDARD_SAPI_MODULE_PROPERTIES

};

php 代理服务器-深入理解PHP与WEB服务器交互

在上面的源码目录php/sapi/apache2handler/中,php/sapi目录下放置的是通过SAPI调用的“第三方”。 目录结构如右图所示。 目录 php/sapi/apache2handler 都是与 PHP 交互的“第三方”。 套接字 sapi_apache2.c 是 PHP 和 Apache 之间约定的 SAPI 套接字文件。

听完这里,你应该对PHP层如何调用服务器层的socket有一个基本的了解了。 为了巩固里面的知识,这里举个栗子,就是在Apache服务器环境下读取cookie:

SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);

当加载任何服务器时,我们将指定 sapi_module。 Apache的sapi_module是apache2_sapi_module,它的read_cookies方法是php_apache_sapi_read_cookies函数。 这样,PHP层就调用了Apache套接字。 是不是很简单呢?

推荐阅读:

如何利用 Shell 脚本来自动监控 Linux 系统的内存?

如何去写一手好SQL?

Linux简介及最常用命令(简单易学能解决95%以上的问题)  

PHP进阶学习之垃圾回收机制详解

PHP7中I/O模型内核剖析详解
Nginx为什么高效?一文搞明白Nginx核心原理
MySQL索引和SQL调优手册
面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来...

面试常考!缓存三大问题及解决方案

·END·
 

PHP开源社区
进阶·提升·涨薪

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 php php 代理服务器-深入理解PHP与WEB服务器交互 https://www.wkzy.net/game/184922.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务