`
wdhdmx
  • 浏览: 304406 次
  • 性别: Icon_minigender_1
  • 来自: 山西
博客专栏
D4bbb5f7-9aa4-3e66-8194-f61b3f0241c2
天天编程
浏览量:21967
社区版块
存档分类
最新评论

fastcgi中的多线程使用

阅读更多

0.背景

在项目中加入了等待通讯的内容,所以原来单个请求处理时间增加了。单线程处理的fcgi就会浪费CPU和用户时间,所以需要多线程来处理,减少用户排队时间。

将处理用户请求的部分从单线程变为多线程,需要大概了解改动会不会影响性能。

得到的结论是:多线程和单线程在执行的流程和使用方法几乎一样,所以多线程不会带来额外的负担。

1.单线程的处理步骤

1.1一个简单的单线程fcgi请求

    #include <fcgi_stdio.h>

    void main(void)
    {
        int count = 0;
        while(FCGI_Accept() >= 0) {
            printf("Content-type: text/html\r\n");
            printf("\r\n");
            printf("Hello world!<br>\r\n");
            printf("Request number %d.", count++);
        }
        exit(0);
    }

1.2进入FCGI_Accept。

进入这个 FCGI_Accept() 方法里面,在文件fcgi_stdio.c里。

int FCGI_Accept(void)
{
    //变量表示是否接收请求。默认为Fasle,不接收请求
    if(!acceptCalled) {
        //判断是否为cgi,变量为全局静态的,下次还会用。
        isCGI = FCGX_IsCGI();
        //状态改为接收请求。
        acceptCalled = TRUE;
        //请求的收尾,将数值清空赋初值。
        atexit(&FCGI_Finish);
    } else if(isCGI) {
        //不是第一次请求,并且是cgi程序。
        return(EOF);
    }
    if(isCGI) {
        //cgi的初始赋值操作,不关心。
        ...
    } else {
        FCGX_Stream *in, *out, *error;
        //char** 字符串数组。
        FCGX_ParamArray envp;
        //接受请求,这个方法下面介绍
        int acceptResult = FCGX_Accept(&in, &out, &error, &envp);
        //接收失败,返回<0,这也是为什么在循环上判断是 while(FCGI_Accept() >= 0)
        if(acceptResult < 0) {
            return acceptResult;
        }
        //将得到的数据赋值给对应的输出,输入,data。
        FCGI_stdin->stdio_stream = NULL;
        FCGI_stdin->fcgx_stream = in;
        FCGI_stdout->stdio_stream = NULL;
        FCGI_stdout->fcgx_stream = out;
        FCGI_stderr->stdio_stream = NULL;
        FCGI_stderr->fcgx_stream = error;
        environ = envp;
    }
    //结束
    return 0;
}

1.3  FCGX_Accept (&in, &out, &error, &envp)

等待接收请求的方法,在fcgiaoo.c里。

static FCGX_Request the_request;

int FCGX_Accept(FCGX_Stream **in,FCGX_Stream **out,FCGX_Stream **err,FCGX_ParamArray *envp)
{
    int rc;//定义返回的变量。
    //是否初始化过。
    if (! libInitialized) {
        rc = FCGX_Init();
        if (rc) {
            return rc;
        }
    }
    //接收数据,下面介绍
    rc = FCGX_Accept_r(&the_request);
    //给对应流和数据赋值。
    *in = the_request.in;
    *out = the_request.out;
    *err = the_request.err;
    *envp = the_request.envp;

    return rc;
}

1.4 FCGX_Accept_r (),同在fcgiapp.c里面;

/*
 *----------------------------------------------------------------------
 *
 * FCGX_Accept_r --
 *
 *      从http server 接收一个新的请求
 * Results:
 *      正确返回0,错误返回-1.
 * Side effects:
 *
 *      通过FCGX_Accept完成请求的接收,创建input,output等流并且各自分配给in
 *      ,out,err.创建参数数据从FCGX_GetParam中取出,并且给envp。
 *      不要保存指针和字符串,他们会在下次请求中的FcGX_Finish中被释放。
 *----------------------------------------------------------------------
 */
int FCGX_Accept_r(FCGX_Request *reqDataPtr)
{
    if (!libInitialized) {
        return -9998;
    }

    //将当前的reqData完成请求。将内容释放,初始化。
    FCGX_Finish_r(reqDataPtr);
    //while
    for (;;) {
        //ipcFd 是双方通讯的管道,在上面的FCGX_Finish_r中被赋值-1。
        if (reqDataPtr->ipcFd < 0) {
            int fail_on_intr = reqDataPtr->flags & FCGI_FAIL_ACCEPT_ON_INTR;
            //接收一次请求,传入socket,没有请求会在这里等待。这里面是重点,可是我看不懂。
            reqDataPtr->ipcFd = OS_Accept(reqDataPtr->listen_sock, fail_on_intr, webServerAddressList);
            if (reqDataPtr->ipcFd < 0) {
                return (errno > 0) ? (0 - errno) : -9999;
            }
        }
        reqDataPtr->isBeginProcessed = FALSE;
        reqDataPtr->in = NewReader(reqDataPtr, 8192, 0);
        FillBuffProc(reqDataPtr->in);
        if(!reqDataPtr->isBeginProcessed) {
            goto TryAgain;
        }
        {
            //查看请求类型。
            char *roleStr;
            switch(reqDataPtr->role) {
                case FCGI_RESPONDER:
                    roleStr = "FCGI_ROLE=RESPONDER";
                    break;
                case FCGI_AUTHORIZER:
                    roleStr = "FCGI_ROLE=AUTHORIZER";
                    break;
                case FCGI_FILTER:
                    roleStr = "FCGI_ROLE=FILTER";
                    break;
                default:
                    goto TryAgain;
            }
            //创建存储参数QueryString的空间。
            reqDataPtr->paramsPtr = NewParams(30);
            //将请求类型当做key-value加入参数里。
            PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr));
        }
        //将输入流以制定的方式读取(在哪停止,是否需要跳过请求)
        SetReaderType(reqDataPtr->in, FCGI_PARAMS);
        //将参数读取写入key=value。
        if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->in) >= 0) {
            //跳出循环,否则等下一次请求。
            break;
        }

        //释放这些中间产生的东西。将ipcFd置为-1.
TryAgain:
        FCGX_Free(reqDataPtr, 1);

    } /* for (;;) */
    //将剩下的信息赋值。完成一个请求的开始部分。
    SetReaderType(reqDataPtr->in, FCGI_STDIN);
    reqDataPtr->out = NewWriter(reqDataPtr, 8192, FCGI_STDOUT);
    reqDataPtr->err = NewWriter(reqDataPtr, 512, FCGI_STDERR);
    reqDataPtr->nWriters = 2;
    reqDataPtr->envp = reqDataPtr->paramsPtr->vec;
    return 0;
}

1.5 在接收请求之前执行的FCGX_Finish_r (reqDataPtr),在fcgiapp.c里;

void FCGX_Finish_r(FCGX_Request *reqDataPtr)
{
    int close;

    if (reqDataPtr == NULL) {
        return;
    }

    close = !reqDataPtr->keepConnection;

    if (reqDataPtr->in) {
        close |= FCGX_FClose(reqDataPtr->err);
        close |= FCGX_FClose(reqDataPtr->out);
    close |= FCGX_GetError(reqDataPtr->in);
    }

    FCGX_Free(reqDataPtr, close);
}

 

基本结束了,只能看懂流程。

二 多线程的请求

2.1多线程请求例子

官网多线程的例子,(http://www.fastcgi.com/devkit/examples/threaded.c)

去掉多余的输出。

 

#define THREAD_COUNT 20

static int counts[THREAD_COUNT];

static void *doit(void *a)
{
    int rc;
    FCGX_Request request;
    FCGX_InitRequest(&request, 0, 0);
    for (;;)
    {
        rc = FCGX_Accept_r(&request);

        if (rc < 0)
            break;
        FCGX_FPrintF(request.out,
            "Content-type: text/html\r\n"
            "\r\n"
            "<title>FastCGI Hello! ");

        sleep(2);
        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;
}

2.2和fcgi有关的方法

在main方法里

FCGX_Init();
Initilize the FCGX library.  This is called by FCGX_Accept()
but must be called by the user when using FCGX_Accept_r().

在多线程里:

    FCGX_Request request;
    FCGX_InitRequest(&request, 0, 0);
    while(){
    rc = FCGX_Accept_r(&request);
    FCGX_FPrintF(request.out,"");
    FCGX_Finish_r(&request);
    }

3.结束

刚刚开始用C语言,希望说错的地方大家提出来。

分享到:
评论

相关推荐

    Java的FastCGI网关 jFastCGI

    此外,FastCGI支持多线程和多进程模型,可以处理大量并发请求,提高了服务器的响应速度。 **jFastCGI介绍** jFastCGI是Java实现的FastCGI客户端,它允许Java应用程序作为FastCGI服务器运行,与使用PHP、Perl或...

    Fastcgi 中文参考手册(DOC).rar

    2. **多进程/线程模型**:根据服务器配置,FastCGI可以采用多进程或者多线程模型,实现并行处理,提升性能。 3. **数据传输**:Web服务器通过TCP或Unix域套接字与FastCGI进程通信,传递请求和接收响应。 4. **协议...

    用VC++开发FastCGI+MySQL的基本源代码

    9. **多线程编程**:根据FastCGI的常驻进程特性,可能需要利用多线程来处理并发请求,这就需要掌握Windows API或C++标准库提供的线程管理功能。 通过这个项目,初学者不仅可以学习到FastCGI与MySQL的基本结合,还能...

    java多线程tcpsocketserver源码-fastcgi:fastcgi

    Java多线程TCP Socket服务器源码与FastCGI:FastCGI详解 在Java编程领域,构建一个高效的多线程TCP Socket服务器是实现高性能网络应用的关键。本篇将深入探讨如何利用Java实现这样的服务器,并结合FastCGI协议,让...

    ISAPI Filter 限制 IIS 多线程访问 .rar

    然而,如果不正确地配置或使用,ISAPI过滤器可能会引发一些问题,比如限制了IIS的多线程访问。 在"ISAPI Filter 限制 IIS 多线程访问"这个主题中,主要关注的是ISAPI过滤器如何可能影响IIS的并发处理能力。IIS作为...

    多线程服务器的适用场合-陈硕1

    然而,在Linux环境中,由于fork()系统调用无法克隆全部线程,多线程进程在需要使用fork()时面临挑战,例如在实现看门狗进程时。 3. 多个单线程进程:这是目前的主流模式,可以通过复制进程来扩展服务,常见的实现...

    java多线程tcpsocketserver源码-FastCGI:FastCGI库(fcgi-2.4.1-SNAP-0311112127)

    综上所述,"java多线程tcp socket server源码-FastCGI:FastCGI库(fcgi-2.4.1-SNAP-0311112127)"涉及的主要知识点包括Java的Socket编程、多线程处理、线程池、FastCGI协议以及网络服务的性能优化。通过深入理解和实践...

    java多线程tcpsocketserver源码-fastcgi-2.4.0:学习cgi+nginx+C++

    7. **开源系统**:标签“系统开源”表明这个Java多线程TCP Socket服务器源码是开放源代码的,允许用户查看、使用、修改和分发代码,这对于学习和改进现有软件是非常有价值的。 学习这个项目,你可以深入理解Java的...

    Apache服务器FastCGI配置教程

    在文档中,还提到了一些Apache的扩展模块,如libapr1和libaprutil1,它们是Apache的底层库,提供了对多线程和数据库访问等功能的支持。这些库的安装对于确保Apache服务器的完整功能和性能非常重要。libaprutil1-dbd-...

    java多线程tcpsocketserver源码-FastCGI-CPP:FastCGI-CPP

    此时,我们可以在新线程中处理这个连接,从而实现多线程处理并发连接,避免单线程模型下的阻塞问题。 ```java ServerSocket serverSocket = new ServerSocket(8080); while (true) { Socket clientSocket = ...

    java多线程tcpsocketserver源码-fastcgi-2:FastCGI开发工具包http://www.fastcgi.com

    Java多线程TCP Socket服务器源码与FastCGI开发工具包是Web服务器和应用程序之间通信的重要技术。在本文中,我们将深入探讨这两个概念及其在实际应用中的作用。 首先,让我们来了解一下Java多线程TCP Socket服务器。...

    PHP中多线程的两个实现方法

    总的来说,PHP中实现多线程主要依靠模拟,如使用子进程、异步I/O或者第三方扩展。选择哪种方法取决于应用场景、服务器环境以及对并发处理的需求。在某些场景下,使用队列和异步任务处理(如Redis、Beanstalkd或...

    luafcgid:具有状态Lua脚本的高性能,多线程FastCGI服务器

    luafcgid是在BSD / Linux下运行的多线程FastCGI服务器。 它管理许多独立的,持久的Lua状态,然后从文件系统中加载Lua脚本。 这些脚本可按需加载/初始化,并在内存中保留尽可能长的时间。 还允许Lua脚本与FastCGI库...

    Java的FastCGI网关 jFastCGI.7z

    FastCGI的主要优点包括持久连接、进程管理以及多线程支持,这些特性使得它相比传统的CGI更加快速和高效。jFastCGI库允许Java应用程序以FastCGI客户端的身份运行,与FastCGI服务器(如Apache、Nginx等)进行通信,...

    基于java的的FastCGI网关 jFastCGI.zip

    1. **高效通信**:jFastCGI使用非阻塞I/O模型,支持多线程和异步处理,能有效处理大量并发请求。 2. **易用性**:提供简单的API接口,使得Java开发者能够快速地集成FastCGI功能。 3. **跨平台**:作为Java库,...

    java多线程tcpsocketserver源码-FastCGI:来自OpenMarket的FastCGI实现的副本以及一些有用的补丁

    Java多线程TCP Socket服务器源码是用于构建高性能、可扩展网络服务的基础,尤其是在Web服务器与应用程序服务器之间交互时,如FastCGI协议所描述的那样。FastCGI是由OpenMarket开发的一种通信协议,旨在提高CGI(通用...

    java源码:Java的FastCGI网关 jFastCGI.rar

    3. **多线程编程**:由于FastCGI服务器通常需要处理多个并发请求,jFastCGI会使用多线程模型来并发处理请求。分析源码可以学习到如何在Java中有效地管理和同步线程。 4. **Java Servlet API**:jFastCGI可能与Java ...

    FastCgi的C++封装类

    5. **多线程或异步处理**:为了提高并发性,封装类可能需要支持多线程或异步处理。这样,当一个请求正在处理时,其他请求可以同时进行,从而提高整体性能。 6. **路由和分发**:在大型应用中,可能需要根据URL或...

    基于Java的实例源码-的FastCGI网关 jFastCGI.zip

    4. **性能优化**:研究如何优化处理速度,例如使用多线程处理请求,或者利用Java并发库来提升性能。 5. **测试与调试**:了解如何编写测试用例,验证FastCGI网关的正确性和性能。 总结,jFastCGI是Java环境下实现...

Global site tag (gtag.js) - Google Analytics