StarTrack

导航

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

 

posted on 2017-06-01 17:57  StarTrack  阅读(1432)  评论(0)    收藏  举报