码迷,mamicode.com
首页 > 编程语言 > 详细

FCGI单线程环境和多线程环境下的例子

时间:2015-01-21 15:10:00      阅读:391      评论:0      收藏:0      [点我收藏+]

标签:fastcgi   服务器   

0.背景

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

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

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

1.单线程的处理步骤

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

C代码  技术分享
  1. #include <fcgi_stdio.h>  
  2.   
  3. void main(void)  
  4. {  
  5.     int count = 0;  
  6.     while(FCGI_Accept() >= 0) {  
  7.         printf("Content-type: text/html\r\n");  
  8.         printf("\r\n");  
  9.         printf("Hello world!<br>\r\n");  
  10.         printf("Request number %d.", count++);  
  11.     }  
  12.     exit(0);  
  13. }  

1.2进入FCGI_Accept。

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

C代码  技术分享
  1. int FCGI_Accept(void)  
  2. {  
  3.     //变量表示是否接收请求。默认为Fasle,不接收请求  
  4.     if(!acceptCalled) {  
  5.         //判断是否为cgi,变量为全局静态的,下次还会用。  
  6.         isCGI = FCGX_IsCGI();  
  7.         //状态改为接收请求。  
  8.         acceptCalled = TRUE;  
  9.         //请求的收尾,将数值清空赋初值。  
  10.         atexit(&FCGI_Finish);  
  11.     } else if(isCGI) {  
  12.         //不是第一次请求,并且是cgi程序。  
  13.         return(EOF);  
  14.     }  
  15.     if(isCGI) {  
  16.         //cgi的初始赋值操作,不关心。  
  17.         ...  
  18.     } else {  
  19.         FCGX_Stream *in, *out, *error;  
  20.         //char** 字符串数组。  
  21.         FCGX_ParamArray envp;  
  22.         //接受请求,这个方法下面介绍  
  23.         int acceptResult = FCGX_Accept(&in, &out, &error, &envp);  
  24.         //接收失败,返回<0,这也是为什么在循环上判断是 while(FCGI_Accept() >= 0)  
  25.         if(acceptResult < 0) {  
  26.             return acceptResult;  
  27.         }  
  28.         //将得到的数据赋值给对应的输出,输入,data。  
  29.         FCGI_stdin->stdio_stream = NULL;  
  30.         FCGI_stdin->fcgx_stream = in;  
  31.         FCGI_stdout->stdio_stream = NULL;  
  32.         FCGI_stdout->fcgx_stream = out;  
  33.         FCGI_stderr->stdio_stream = NULL;  
  34.         FCGI_stderr->fcgx_stream = error;  
  35.         environ = envp;  
  36.     }  
  37.     //结束  
  38.     return 0;  
  39. }  

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

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

C代码  技术分享
  1. static FCGX_Request the_request;  
  2.   
  3. int FCGX_Accept(FCGX_Stream **in,FCGX_Stream **out,FCGX_Stream **err,FCGX_ParamArray *envp)  
  4. {  
  5.     int rc;//定义返回的变量。  
  6.     //是否初始化过。  
  7.     if (! libInitialized) {  
  8.         rc = FCGX_Init();  
  9.         if (rc) {  
  10.             return rc;  
  11.         }  
  12.     }  
  13.     //接收数据,下面介绍  
  14.     rc = FCGX_Accept_r(&the_request);  
  15.     //给对应流和数据赋值。  
  16.     *in = the_request.in;  
  17.     *out = the_request.out;  
  18.     *err = the_request.err;  
  19.     *envp = the_request.envp;  
  20.   
  21.     return rc;  
  22. }  

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

C代码  技术分享
  1. /* 
  2.  *---------------------------------------------------------------------- 
  3.  * 
  4.  * FCGX_Accept_r -- 
  5.  * 
  6.  *      从http server 接收一个新的请求 
  7.  * Results: 
  8.  *      正确返回0,错误返回-1. 
  9.  * Side effects: 
  10.  * 
  11.  *      通过FCGX_Accept完成请求的接收,创建input,output等流并且各自分配给in 
  12.  *      ,out,err.创建参数数据从FCGX_GetParam中取出,并且给envp。 
  13.  *      不要保存指针和字符串,他们会在下次请求中的FcGX_Finish中被释放。 
  14.  *---------------------------------------------------------------------- 
  15.  */  
  16. int FCGX_Accept_r(FCGX_Request *reqDataPtr)  
  17. {  
  18.     if (!libInitialized) {  
  19.         return -9998;  
  20.     }  
  21.   
  22.     //将当前的reqData完成请求。将内容释放,初始化。  
  23.     FCGX_Finish_r(reqDataPtr);  
  24.     //while  
  25.     for (;;) {  
  26.         //ipcFd 是双方通讯的管道,在上面的FCGX_Finish_r中被赋值-1。  
  27.         if (reqDataPtr->ipcFd < 0) {  
  28.             int fail_on_intr = reqDataPtr->flags & FCGI_FAIL_ACCEPT_ON_INTR;  
  29.             //接收一次请求,传入socket,没有请求会在这里等待。这里面是重点,可是我看不懂。  
  30.             reqDataPtr->ipcFd = OS_Accept(reqDataPtr->listen_sock, fail_on_intr, webServerAddressList);  
  31.             if (reqDataPtr->ipcFd < 0) {  
  32.                 return (errno > 0) ? (0 - errno) : -9999;  
  33.             }  
  34.         }  
  35.         reqDataPtr->isBeginProcessed = FALSE;  
  36.         reqDataPtr->in = NewReader(reqDataPtr, 8192, 0);  
  37.         FillBuffProc(reqDataPtr->in);  
  38.         if(!reqDataPtr->isBeginProcessed) {  
  39.             goto TryAgain;  
  40.         }  
  41.         {  
  42.             //查看请求类型。  
  43.             char *roleStr;  
  44.             switch(reqDataPtr->role) {  
  45.                 case FCGI_RESPONDER:  
  46.                     roleStr = "FCGI_ROLE=RESPONDER";  
  47.                     break;  
  48.                 case FCGI_AUTHORIZER:  
  49.                     roleStr = "FCGI_ROLE=AUTHORIZER";  
  50.                     break;  
  51.                 case FCGI_FILTER:  
  52.                     roleStr = "FCGI_ROLE=FILTER";  
  53.                     break;  
  54.                 default:  
  55.                     goto TryAgain;  
  56.             }  
  57.             //创建存储参数QueryString的空间。  
  58.             reqDataPtr->paramsPtr = NewParams(30);  
  59.             //将请求类型当做key-value加入参数里。  
  60.             PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr));  
  61.         }  
  62.         //将输入流以制定的方式读取(在哪停止,是否需要跳过请求)  
  63.         SetReaderType(reqDataPtr->in, FCGI_PARAMS);  
  64.         //将参数读取写入key=value。  
  65.         if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->in) >= 0) {  
  66.             //跳出循环,否则等下一次请求。  
  67.             break;  
  68.         }  
  69.   
  70.         //释放这些中间产生的东西。将ipcFd置为-1.  
  71. TryAgain:  
  72.         FCGX_Free(reqDataPtr, 1);  
  73.   
  74.     } /* for (;;) */  
  75.     //将剩下的信息赋值。完成一个请求的开始部分。  
  76.     SetReaderType(reqDataPtr->in, FCGI_STDIN);  
  77.     reqDataPtr->out = NewWriter(reqDataPtr, 8192, FCGI_STDOUT);  
  78.     reqDataPtr->err = NewWriter(reqDataPtr, 512, FCGI_STDERR);  
  79.     reqDataPtr->nWriters = 2;  
  80.     reqDataPtr->envp = reqDataPtr->paramsPtr->vec;  
  81.     return 0;  
  82. }  

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

C代码  技术分享
  1. void FCGX_Finish_r(FCGX_Request *reqDataPtr)  
  2. {  
  3.     int close;  
  4.   
  5.     if (reqDataPtr == NULL) {  
  6.         return;  
  7.     }  
  8.   
  9.     close = !reqDataPtr->keepConnection;  
  10.   
  11.     if (reqDataPtr->in) {  
  12.         close |= FCGX_FClose(reqDataPtr->err);  
  13.         close |= FCGX_FClose(reqDataPtr->out);  
  14.     close |= FCGX_GetError(reqDataPtr->in);  
  15.     }  
  16.   
  17.     FCGX_Free(reqDataPtr, close);  
  18. }  

 

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

二 多线程的请求

2.1多线程请求例子

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

去掉多余的输出。

 

C代码  技术分享
  1. #define THREAD_COUNT 20  
  2.   
  3. static int counts[THREAD_COUNT];  
  4.   
  5. static void *doit(void *a)  
  6. {  
  7.     int rc;  
  8.     FCGX_Request request;  
  9.     FCGX_InitRequest(&request, 0, 0);  
  10.     for (;;)  
  11.     {  
  12.         rc = FCGX_Accept_r(&request);  
  13.   
  14.         if (rc < 0)  
  15.             break;  
  16.         FCGX_FPrintF(request.out,  
  17.             "Content-type: text/html\r\n"  
  18.             "\r\n"  
  19.             "<title>FastCGI Hello! ");  
  20.   
  21.         sleep(2);  
  22.         FCGX_Finish_r(&request);  
  23.     }  
  24.     return NULL;  
  25. }  
  26.   
  27. int main(void)  
  28. {  
  29.     int i;  
  30.     pthread_t id[THREAD_COUNT];  
  31.   
  32.     FCGX_Init();  
  33.   
  34.     for (i = 1; i < THREAD_COUNT; i++)  
  35.         pthread_create(&id[i], NULL, doit, (void*)i);  
  36.   
  37.     doit(0);  
  38.     return 0;  
  39. }  

2.2和fcgi有关的方法

在main方法里

C代码  技术分享
  1. FCGX_Init();  
  2. Initilize the FCGX library.  This is called by FCGX_Accept()  
  3. but must be called by the user when using FCGX_Accept_r().  

在多线程里:

C代码  技术分享
  1. FCGX_Request request;  
  2. FCGX_InitRequest(&request, 0, 0);  
  3. while(){  
  4. rc = FCGX_Accept_r(&request);  
  5. FCGX_FPrintF(request.out,"");  
  6. FCGX_Finish_r(&request);  
  7. }  

FCGI单线程环境和多线程环境下的例子

标签:fastcgi   服务器   

原文地址:http://blog.csdn.net/nyist327/article/details/42968521

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!