谢邀
cgi 是一个协议,fastcgi是一个高级协议,这个就跟我们常用的http和https协议是一个道理.
php-cgi 负责解析cgi和fastcgi的程序而已
php-fpm 一个管理进程的进程管理器而已.他管理的是实现了能够解析cgi和fastcgi的程序而已,这个更通常的称之为sapi(服务器端应用编程端口)
现在我们来说说你的问题
1. nginx没有能力解析PHP,所以他通过实现fastcgi协议,然后把消息发送给我们的php-fpm,fpm就根据对应的模式来找寻对应的php-cgi来解析并返回给我们的nginx.至于一定要配置fpm么,答案是否定的.我可以通过转发给apache直接用cgi来解析也是可以的.
2. php-fpm和fastcgi都不管解析的事情,实际上负责解析的是我们的php-cgi
3. 至于php-fpm和fastcgi和php-cgi的关系我在上面已经说明了.
4. 他的说法是对的.但是php-fpm不是实现这个接口的东西.按照源码来说,正确实现这个解析的是php-cgi.
不懂的可以去看一下php7-internal这个作者所写的.写的挺不错的.
只有第4点,为撒会这么说.这个是根据php-fpm的源码来看的.php-fpm不会解析和处理请求.具体的请求处理都是在worker中,暂且称之为php-cgi吧.具体的fpm实现大概是这个样子的.
int main(int argc, char *argv[])
{
sapi_startup(&cgi_sapi_module); // 注册SAPI:将全局变量sapi_module设置为cgi_sapi_module
...
fcgi_init(); // 初始化fastcgi协议,不解析,这回会返回一个值判断是否为fastcgi
...
// 这里初始化fpm
if (0 > fpm_init(argc, argv, fpm_config ? fpm_config : CGIG(fpm_config), fpm_prefix, fpm_pid, test_conf, php_allow_to_run_as_root, force_daemon, force_stderr)) {
...
}
...
if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) { // 启动模块
#ifdef ZTS
tsrm_shutdown();
#endif
return FPM_EXIT_SOFTWARE;
}
...
fcgi_fd = fpm_run(&max_requests); // 获取worker进程,master将不再执行下面.由worker来处理我们的请求
...
/* library is already initialized, now init our request */
request = fpm_init_request(fcgi_fd);
}
// fpm_run函数
int fpm_run(int *max_requests) /* {{{ */
{
struct fpm_worker_pool_s *wp;
// 编译worker pool
for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
int is_parent;
//调用fpm_children_make() fork子进程
is_parent = fpm_children_create_initial(wp);
if (!is_parent) {
// fork 出的worker进程
goto run_child;
}
/* handle error */
if (is_parent == 2) {
fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
fpm_event_loop(1);
}
}
// master进入event循环,不在往下走.
fpm_event_loop(0);
run_child:
fpm_cleanups_run(FPM_CLEANUP_CHILD);
*max_requests = fpm_globals.max_requests;
return fpm_globals.listening_socket;
}
暂且就说这么多吧,实际上还有一些例如phpinfo这个函数,是直接在php-fpm里面完成的,非常有技巧,一个常驻地址.
if (php_information) { // 大约在/sapi/fpm/fpm_main.c 1746行左右
cgi_sapi_module.phpinfo_as_text = 1;
cgi_sapi_module.startup(&cgi_sapi_module);
// 启用请求
if (php_request_startup() == FAILURE) {
SG(server_context) = NULL;
php_module_shutdown();
return FPM_EXIT_SOFTWARE;
}
SG(headers_sent) = 1;
SG(request_info).no_headers = 1;
// 直接就用0xFFFFFFFF这个地址了.
php_print_info(0xFFFFFFFF);
// 请求处理结束
php_request_shutdown((void *) 0);
fcgi_shutdown();
exit_status = FPM_EXIT_OK;
// 直接就跑到最后去了.
goto out;
}
@熊猫桑 @上官元恒 你们肿么看 其实我也说的不是很对.大概是这个样子的.