CGI——公共网关接口(common gateway interface)
使用CGI处理写有数据的动态请求(比如登录)
nginx通过cgi来处理数据。nginx只处理静态请求,对于数据处理,post、get的时候,nginx只能解析,他需要使用第三方的接口——fastCGI。
CGI是什么?
- 公共网关接口
- Common Gateway Interface, 简称CGI
- 在物理层面上是一段程序, 运行在服务器上,提供同客户端HTML页面的接口
处理步骤:
- 通过Internet把用户请求送到Web服务器
- Web服务器接收到用户请求并交给CGI程序
- CGI程序把处理结果传送给Web服务器
- Web服务器把结果送回到用户
CGI程序是如何工作的:
- web服务器(ngxin) , 收到一个请求
- web服务器fork一个子进程,每处理一请求, 都会创建一个子进程
- 数据处理完成之后, 该cgi进程会被web服务器杀死
CGI的弊端
- 需要频繁的创建和销毁进程
- web服务器效率低
改进:
- 使用fastCGI——将cgi进行了改进
直接使用CGI进行图片上传的示意图
使用fastCGI进行图片上传的示意图
fastCGI(跨平台,在PHP里面用的多)
1、什么是fastCGI
- FastCGI是语言无关的、可伸缩架构的CGI开放扩展
- 其主要行为是将CGI解释器进程保持在内存中进行管理调度因此获得较高的性能
2、FastCGI的工作原理是:
- Web Server 启动时载入FastCGI进程管理器
- FastCGI进程管理器自身初始化,启动多个CGI解释器进程 并等待来自Web Server的连接
- 当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器
- FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server
3、杯具的事情:
- nginx 下 fastcgi 与服务器是分离的,nginx不能直接调用fastCGI,在PHP里面可以直接调用
- fastcgi 可使用spawn-fcgi 或者 php-fpm 来进行nginx和fastCGI之间进行通信
fastCGI和spawn-fcgi的安装
安装包获取链接:https://pan.baidu.com/s/1R_NVOFGNAR3Jy93Y5O-hcA
两个安装包分别解压并安装
./configure
make
make install
在安装包中往往会有一些例子,可以帮助我们了解如何使用api
分析example文件夹里面的ecoh.c
阅读完代码之后,发现该文件的功能是——把收到的数据打印到浏览器,并将环境变量也打印到浏览器。
/*
* echo.c --
*
* Produce a page containing all FastCGI inputs
*
*
* Copyright (c) 1996 Open Market, Inc.
*
* See the file "LICENSE.TERMS" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#ifndef lint
static const char rcsid[] = "$Id: echo.c,v 1.5 1999/07/28 00:29:37 roberts Exp $";
#endif /* not lint */
#include "fcgi_config.h"
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef _WIN32
#include <process.h>
#else
//使用extern声明的变量,environ就是一个全局变量(经验)
extern char **environ;
#endif
#include "fcgi_stdio.h"
static void PrintEnv(char *label, char **envp)
{
printf("%s:<br>\n<pre>\n", label);
for ( ; *envp != NULL; envp++) {
printf("%s\n", *envp);
}
printf("</pre><p>\n");
}
int main ()
{
char **initialEnv = environ;
int count = 0;
//FCGI_Accept,fastcgi提供的api,就是上面例子中用于上传图片并且不会退出的进程
//保证其不退出的原理是有任务就进入while循环中,任务完成就阻塞等待在while循环的入口
while (FCGI_Accept() >= 0) {
//getenv——系统函数,用于打印环境变量的内容。
//CONTENT_LENGTH——一个环境变量,表示接受的数据长度
//CONTENT_LENGTH对应http请求第四部分的数据的内容
//只有post请求时,环境变量的值才>0
char *contentLength = getenv("CONTENT_LENGTH");
int len;
printf("Content-type: text/html\r\n"
"\r\n"
"<title>FastCGI echo</title>"
"<h1>FastCGI echo</h1>\n"
"Request number %d, Process ID: %d<p>\n", ++count, getpid());
//说明CONTENT_LENGTH环境变量不为空
if (contentLength != NULL) {
//strtol是一个转换函数,用atoi也可以。
//strtol的三个参数:待转换的字符串、与是否输出调试信息有关的参数、转换的进制
len = strtol(contentLength, NULL, 10);
}
else {
//说明CONTENT_LENGTH环境变量为空
len = 0;
}
if (len <= 0) {
printf("No data from standard input.<p>\n");
}
else {
//此时说明有post数据
int i, ch;
printf("Standard input:<br>\n<pre>\n");
//将post数据读出来getchar获取数据,putchar将数据打印出来
for (i = 0; i < len; i++) {
if ((ch = getchar()) < 0) {
printf("Error: Not enough bytes received on standard input<p>\n");
break;
}
putchar(ch);
}
printf("\n</pre><p>\n");
}
//打印一些环境变量
PrintEnv("Request environment", environ);
PrintEnv("Initial environment", initialEnv);
} /* while */
return 0;
}
试着跑一下这个程序
gcc echo.c -lfcgi
结果出现错误:
./a.out: error while loading shared libraries: libfcgi.so.0: cannot open shared object file: No such file or directory
动态库找不到,于是按照 https://blog.csdn.net/qq_29996285/article/details/86744372 的方法做了一遍还是不行。google到了解决方案:
把 libfcgi.so.0
在 /usr/lib64/
和 /usr/lib/
里都链接了一份
skyyuan:~ $ sudo ln -s /usr/local/lib/libfcgi.so.0.0.0 /usr/lib/libfcgi.so.0
skyyuan:~ $ sudo ln -s /usr/local/lib/libfcgi.so.0.0.0 /usr/lib64/libfcgi.so.0
问题解决了。解决该问题的文章:http://ju.outofmemory.cn/entry/110241
运行结果:
spawn-fcgi
作用:
- 相当一个代理工具,
- 角色完成nginx和fastcgi之间的进程间通信
框架
- nginx收到不能处理的数据之后,将数据发送出去,要把数据发送到指定的端口(一个端口对应一个进程)。
- spawn-fcgi监听端口,接收到待处理数据,将收到的数据转发给fastCGI
- fastCGI进程是spawn-fcgi的子进程,通过fork产生子进程
- fastCGI将处理好的数据回复给父进程spawn-fcgi(实现原理——父进程将子进程的标准输出重定向到管道的写端,父进程读管道就能获取子进程的返回值了)
- spawn-fcgi将处理好后的数据转发给nginx
配置
nginx配置fastCGI
nginx将处理不了的指令发送给fastCGI,发送到指定的端口
修改nginx.conf文件
#处理一个指令test
#url:http://192.168.82.253/test
location /test{
#配置fastCGI模块,设置将数据发送给本机的8002端口
fastcgi_pass localhost:9001;
#另一种写法
#fastcgi_pass 127.0.0.1:9001;
#包含文件fastCGI.conf。这个配置文件中都是一些环境变量
include fastCGI.conf;
}
fastcgi.conf文件的位置
spawn-fcgi的使用
第一步
- 编写一个fcgi程序编译出来的程序名为“a.out”(就是上面的echo.c的编译产出)
第二步
- 输入shell命令执行fcgi程序
spawn-fcgi -a IP -p 端口号 -f fastcgi程序
- -a - IP: 服务器IP地址
- -p - port: 服务器将数据发送到的端口
- -f - cgi程序: spawn-fcgi启动的可执行fastcgi程序
测试一下,执行echo.c的编译产出“a.out”。下图中,spawn-fcgi开启成功了(注意:ip地址和端口号要与nginx.conf里面设置的保持一致)
关于fastCGI的使用
1、环境变量指针
- extern char **__environ;
- 头文件: /usr/include/unistd.h
2、FCGI_Accept()
3、fastcgi.conf中常用环境变量:
- QUERY_STRING: 请求的资源, 请求行的第二部分
- REQUEST_METHOD: 请求方法, get/post
- CONTENT_TYPE: 文件类型
- SCRIPT_NAME: 处理的指令, nginx中配置cgi的时候用
- REQUEST_URI: 浏览器中请求的资源, 不包括IP+por