项目(4)(cgi、fastCGI、spawn-fcgi)

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之间的进程间通信

 框架

  1. nginx收到不能处理的数据之后,将数据发送出去,要把数据发送到指定的端口(一个端口对应一个进程)。
  2. spawn-fcgi监听端口,接收到待处理数据,将收到的数据转发给fastCGI
  3. fastCGI进程是spawn-fcgi的子进程,通过fork产生子进程
  4. fastCGI将处理好的数据回复给父进程spawn-fcgi(实现原理——父进程将子进程的标准输出重定向到管道的写端,父进程读管道就能获取子进程的返回值了
  5. 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

猜你喜欢

转载自blog.csdn.net/qq_29996285/article/details/87787498