fastcgi多线程调用
先贴代码,参考fcgi的example。
#include <stdlib.h> #include <cstdio> #include "cstdlib" #include "unistd.h" #include "string" #include "string.h" #include "strings.h" #include <pthread.h> #include <sys/types.h> #include "fcgi_stdio.h" #include "mysql/mysql.h" #include "hiredis/hiredis.h" #define THREAD_COUNT 16 typedef struct{ int id; pthread_t th; }ThreadInfo; static ThreadInfo gThreadInfos[THREAD_COUNT]; static pthread_mutex_t acceptMutex = PTHREAD_MUTEX_INITIALIZER; int redisFunc(FCGX_Request &request) { struct timeval tv; char str[64]; redisReply *rep = NULL; tv.tv_sec = 10; tv.tv_usec = 0; redisContext *c = redisConnectWithTimeout("127.0.0.1", 6379, tv); if(c->err){ FCGX_FPrintF(request.out, "redisConnectWithTimeout error!\n"); redisFree(c); return -1; } /////////////////////////////////////////////// const char* command1 = "GET testkey"; rep = (redisReply*)redisCommand(c, command1); if(NULL == rep){ redisFree(c); return -1; } if(rep->type != REDIS_REPLY_STRING){ FCGX_FPrintF(request.out, "Failed to execute command[%s] type[%d] <p>",command1, rep->type); freeReplyObject(rep); redisFree(c); return -1; } bzero(str, 64); sprintf(str, "command[%s] value[%s] <p>", command1, rep->str); FCGX_FPrintF(request.out, str); freeReplyObject(rep); /////////////////////////////////////////////// const char *command2 = "HGETALL hashkey"; rep = (redisReply*)redisCommand(c, command2); if(NULL == rep){ redisFree(c); return -1; } if(rep->type != REDIS_REPLY_ARRAY){ FCGX_FPrintF(request.out, "Failed to execute command[%s] type[%d] <p>", command2, rep->type); freeReplyObject(rep); redisFree(c); return -1; } for(uint i = 0; i < (rep->elements - 1); ){ redisReply *field = rep->element[i]; redisReply *value = rep->element[i+1]; if(field && value){ bzero(str, 64); sprintf(str, "field[%s] value[%s] <p>", field->str, value->str); FCGX_FPrintF(request.out, str); } i += 2; } freeReplyObject(rep); /////////////////////////////////////////////// // for(;;){ // printf("redisGetReply\n"); // int ret = redisGetReply(c, (void**)&rep); // if(REDIS_OK != ret || NULL == rep) // break; // std::string str(rep->str); // //FCGX_FPrintF(request.out, str.c_str()); // printf("%s\n", str.c_str()); // freeReplyObject(rep); // } redisFree(c); return 0; } //insert into company values(0, 'twitter', 'social network', 'USA', Now()); //select name,`desc`,country from company order by name int mysqlSelectFunc(FCGX_Request &request) { int ret = 0; MYSQL mysql; MYSQL_RES *res; MYSQL_ROW row; if(!mysql_init(&mysql)){ printf("mysql_init failed!\n"); return 0; } if(!mysql_real_connect(&mysql, "127.0.0.1", "root", "jasondb", "mytest", 0, NULL, 0)){ printf("mysql_real_connect() failed! %s\n", mysql_error(&mysql)); mysql_close(&mysql); return 0; } const char *query = "select name,`desc`,country from company order by name"; ret = mysql_real_query(&mysql, query, strlen(query)); if(ret) { printf("mysql_real_query error! %s\n",mysql_error(&mysql)); mysql_close(&mysql); return -1; } std::string content; res = mysql_store_result(&mysql); content.append("<table border=\"1\">"); while(row = mysql_fetch_row(res)){ content.append("<tr>"); for(uint t=0; t < mysql_num_fields(res); t++){ content.append("<td>"); content.append(row[t]); content.append("</td>"); } content.append("</tr>"); } content.append("</table> <p>"); //printf("%s", content.c_str()); FCGX_FPrintF(request.out, content.c_str()); if(res) mysql_free_result(res); mysql_close(&mysql); } void *fcgiFunc(void *arg) { int rc, i, id = *(int*)(arg); FCGX_Request request; char *server_name; char *content_length; char *query_string; char *http_useragent; char *request_method; char *content_type; pid_t pid = getpid(); FCGX_InitRequest(&request, 0, 0); for(;;){ pthread_mutex_lock(&acceptMutex); rc = FCGX_Accept_r(&request); pthread_mutex_unlock(&acceptMutex); if (rc < 0) break; request_method = FCGX_GetParam("REQUEST_METHOD", request.envp); server_name = FCGX_GetParam("SERVER_NAME", request.envp); content_length = FCGX_GetParam("CONTENT_LENGTH", request.envp); query_string = FCGX_GetParam("QUERY_STRING", request.envp); http_useragent = FCGX_GetParam("HTTP_USER_AGENT", request.envp); content_type = FCGX_GetParam("CONTENT_TYPE", request.envp); FCGX_FPrintF(request.out, "Content-type: text/html\r\n" "\r\n" "<title>The Begining of A Back-ending Way for Developer</title>" "<h1>The Begining of A Back-ending Way for Developer</h1>" "Thread %d, Process %ld<p>" "Request counts for %d threads running on host <i>%s</i><p><code>" "CONTENT_LENGTH %s<p>" "QUERY_STRING %s <p>" //"HTTP_USER_AGENT %s <p>" "CONTENT_TYPE %s <p>" "REQUEST_METHOD %s <p>", id, pid, THREAD_COUNT, server_name ? server_name : "?", content_length, query_string, /*http_useragent,*/ content_type, request_method); mysqlSelectFunc(request); redisFunc(request); if(request_method != NULL){ int len = 0; if(0 == strcmp(request_method, "POST")){ len = atoi(content_length); char *data = (char*)malloc(sizeof(char)*len + 1); fread(data, sizeof(char), len, stdin); if(data){ free(data); data = NULL; } }else if(0 == strcmp(request_method, "GET")){ len = strlen(query_string); } } FCGX_Finish_r(&request); } return NULL; } int main(int argc, char *argv[]) { FCGX_Init(); for(int i = 0; i < THREAD_COUNT; i++){ gThreadInfos[i].id = i; pthread_create(&gThreadInfos[i].th, NULL, fcgiFunc, (void*)&gThreadInfos[i].id); } for(;;) sleep(1); return 0; }
fastcgi为什么要做多线程?我猜测原因可能是当多个用户访问同一个cgi程序时,多线程比多进程更加轻量级一些。同时需要注意的是,多个cgi进程同时运行,需要用文件锁或者信号量进行同步。
再贴个shell脚本,自动更新由spawn-cgi管理的fcgi程序。
#!/bin/sh if [ $# -ne 1 ];then echo "Usage: `basename $0` process_name" exit 1 fi CGIPID=`ps -ef | grep -v "grep" | grep -v "$0" | grep "$1" | awk '{print $2}'` echo "pid is $CGIPID" if [ -z $CGIPID ];then spawn-fcgi -a 127.0.0.1 -p 8081 -f $PWD/$1 else kill $CGIPID spawn-fcgi -a 127.0.0.1 -p 8081 -f $PWD/$1 fi
浙公网安备 33010602011771号