FastCGI学习总结

 

作者: Jimmy Cao,2008/9 All Rights Reserved 共同学习进步,转载请注明

什么是FastCGI

FastCGI :Fast Common Gateway Interface(快速通用网关接口),它是CGI的增强版。FastCGI是一个快速、开放和安全的web server接口,解决了传统CGI的性能问题,却又没有带来编程的复杂性。老的CGI程序可以很轻易的移植成FastCGI程序。

FastCGI的技术原理

如果想了解FastCGI的技术原理就要了解何为"短生存期应用程序",何为"长生存期应用程序"。

先从CGI技术开刀,以下是CGI技术的理论:每次当客户请求一个CGI的时候,Web服务器就请求操作系统生成一个新的CGI进程。当CGI满足要求后,服务器就杀死这个进程。服务器对客户端的每个请求都要重复这样的过程。

而FastCGI技术的理论为:FastCGI程序一旦产生后,他可以持续工作,足够满足客户的请求直到被明确的终止。如果你希望通过协同处理来提高程序的性能,你可以请求Web服务器运行多个FastCGI 应用程序的副本。 CGI就是所谓的短生存期应用程序,FastCGI就是所谓的长生存期应用程序。

由于FastCGI程序并不需要不断的产生新进程,可以大大降低服务器的压力。并且产生较高的应用效率。

FastCGI的特点

  1. 打破传统页面处理技术

传统的页面处理技术,程序必须与Web服务器或Application服务器处于同一台服务器中。这种历史已经早N年被FastCGI技术所打破,FastCGI技术的应用程序可以被安装在服务器群中的任何一台服务器,而通过TCP/IP协议与Web服务器通讯,这样做既适合开发大型分布式Web群,也适合高效数据库控制。

 

  1. 明确的请求模式

CGI技术没有一个明确的角色,在FastCGI程序中,程序被赋予明确的角色(响应器角色(Responder)、认证器角色(Authorizer)、过滤器角色(Filter))。

 

  1. 独立性

架构独立性:FastCGI接口并不绑定特定的应用服务器架构,应用既可以是单线程的也可是多线程的。

进程独立性:FastCGI进程是独立于服务器的进程,对FastCGI进程的调试不影响服务器。同理,FastCGI进程的崩溃也不至于服务器崩溃。

语言独立性:FastCGI技术目前支持语言有:C/C++、Java、Perl、Tcl、Python、SmallTalk、Ruby等。

 

如何开发FastCGI程序

实现细节

先来看看传统CGI是怎么做的,如下图:

 

                                   图一:CGI的数据流

CGI应用是通过标准的POSIX流(stdin, stdout, stderr和环境变量)加上环境变量,来与HTTP服务器进行通信。

 

与CGI类似,FastCGI采用的方法是:在HTTP进程和FastCGI进程之间创建一个全双工的连接,数据报通过FastCGI协议封装在两个进程之间传递。

stdin和环境变量被封装在连接的输入部分;stdout和stderr被封装在连接的输出部分。

因此,作为输入端,FastCGI程序从连接上接收数据,解包,分离出stdin和环境变量,然后调用应用处理逻辑。作为输出端,FastCGI用FastCGI协议打包stdout和stderr,发送给HTTP服务器处理。

 

由于FastCGI应用不要求和HTTP服务器运行在同一个节点上,因此,FastCGI支持两种形式的连接:1)流管道,用于在同一个节点上的通信;2)TCP流,用于不同节点上的通信。

下图是FastCGI应用和HTTP服务器不在同一个机器上的数据流图:

 

图二:FastCGI和HTTP不在同一节点的数据流

程序框架

不同于CGI程序的单次执行特性,FastCGI的主程序框架有一个循环,如下:

 

Initialize application;
while(FCGI_Accept() >= 0) {
Process request;
}

 

初始化部分,只执行一次,所以常常把一些耗时的工作放在此处理,如:打开和连接数据库,计算表和位图值等。

另外初始化部分,还完成环境变量初始化等工作。

 

然后,程序阻塞在FCGI_Accep()调用上,一旦有连接上了就处理,否则就阻塞。

 

一个简单的FastCGI程序实例:

#include "fcgi_stdio.h" /* fcgi library; put it first*/



#include <stdlib.h>
 
int count;
 
void initialize(void)
{
  count=0;
}
 
void main(void)
{
/* Initialization. */  
  initialize();
 
/* Response loop. */
  while (FCGI_Accept() >= 0)   {
    printf("Content-type: text/html\r\n"
           "\r\n"
           "<title>FastCGI Hello! (C, fcgi_stdio library)</title>"
           "<h1>FastCGI Hello! (C, fcgi_stdio library)</h1>"
           "Request number %d running on host <i>%s</i>\n",
            ++count, getenv("SERVER_HOSTNAME"));
  }
}

另外一个例子,多线程编程:

/*
 * threaded.c -- A simple multi-threaded FastCGI application.
 */

#ifndef lint
static const char rcsid[] = "$Id: threaded.c,v 1.9 2001/11/20 03:23:21 robs Exp $";
#endif /* not lint */

#include "fcgi_config.h"

#include <pthread.h>
#include <sys/types.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "fcgiapp.h"


#define THREAD_COUNT 20

static int counts[THREAD_COUNT];

static void *doit(void *a)
{
    int rc, i, thread_id = (int)a;
    pid_t pid = getpid();
    FCGX_Request request;
    char *server_name;

    FCGX_InitRequest(&request, 0, 0);
    for (;;)
    {
        static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
        static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER;

        /* Some platforms require accept() serialization, some don't.. */
        pthread_mutex_lock(&accept_mutex);
        rc = FCGX_Accept_r(&request);
        pthread_mutex_unlock(&accept_mutex);

        if (rc < 0)
            break;

        server_name = FCGX_GetParam("SERVER_NAME", request.envp);

        FCGX_FPrintF(request.out,
            "Content-type: text/html\r\n"
            "\r\n"
            "<title>FastCGI Hello! (multi-threaded C, fcgiapp library)</title>"
            "<h1>FastCGI Hello! (multi-threaded C, fcgiapp library)</h1>"
            "Thread %d, Process %ld<p>"
            "Request counts for %d threads running on host <i>%s</i><p><code>",
            thread_id, pid, THREAD_COUNT, server_name ? server_name : "?");

        sleep(2);

        pthread_mutex_lock(&counts_mutex);
        ++counts[thread_id];
        for (i = 0; i < THREAD_COUNT; i++)
            FCGX_FPrintF(request.out, "%5d " , counts[i]);
        pthread_mutex_unlock(&counts_mutex);

        FCGX_Finish_r(&request);
    }

    return NULL;
}

int main(void)
{
    int i;
    pthread_t id[THREAD_COUNT];

    FCGX_Init();

    for (i = 1; i < THREAD_COUNT; i++)
        pthread_create(&id[i], NULL, doit, (void*)i);

    doit(0);

    return 0;
}

 

c文件编译方式

gcc -o test.fcgi test.c -lpthread -lfcgi

 

附录:CGI常用环境变量

环境变量

说明

ALL_HTTP

未包括在本表格中给出的变量内的所有HTTP标题,如:这个变量来自表格HTTP_<标题栏名称>

QUERY_STRING

传递给程式的 query 信息,即:在指向URL中跟在问号(?)后的信息

REMOTE_HOST

使用者发出 request 的远端 host 名称

REMOTE_ADDR

使用者发出 request 的远端 IP 位址

AUTH_TYPE

用来确定使用者合法性的监定方法

REMOTE_USER

使用者的合法名称

REMOTE_IDENT

发出 request 的使用者

CONTENT_TYPE

query 信息中的 MIME 类型

CONTENT_LENGTH

以字节为单位的从客户端接收来的脚步长度

HTTP_FORM

使用者发出 request 的电子邮件讯息

HTTP_ACCEPT

client 可以接受的 MIME 类型列表

HTTP_COOKIE

与你站点打交道的客户的任何cookie(存储片)集合

HTTP_USER_AGENT

client 用来发出 request 的浏览器

GATEWAY_INTERFACE

Server 使用的 CGI 版本

SERVER_NAME

Server host 名称或 IP 位址

SERVER_SOFTWARE

回应 client request Server 软体名称和版本

SERVER_PROTOCOL

传递资讯所用的协定名称或版本

SERVER_PORT

Server 正在执行的 port number

SERVER_PORT_SECURE

值为01,值1表示请求出现在加密端口

URL

请求的URL地址

REQUEST_METHOD

发出 request 的方法

PATH_INFO

传递给 CGI 程式的额外路径

PATH_TRANSLATED

存在 PATH_INFO 中的给定路径的传递版本

SCRIPT_NAME

程式执行时的 virtual path

DOCUMENT_ROOT

网路提供的文件服务所在路径

HTTP_REFERER

在读取 CGI 程式前,client 所指的文件 URL

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值