Nginx和FastCGI学习之一

Nginx和FastCGI学习之一

参考:
Nginx + CGI/FastCGI + C/Cpp
FastCGI
FastCGI介绍
fcgx_accept_r 返回-88 我的解法
FastCGI的并发处理

代码示例如下:
fastcgidemo.cpp代码:

//fastcgidemo.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <unistd.h>

#include "fcgi_stdio.h"
#include "fcgio.h"  
#include "fcgi_config.h"
#include "log.h"
#include "common.h"
#include "httpscode.hpp"


using namespace std;

void fcgi_work(int count);

int main(void)
{
    int count = 0;
    CLog::InitLog();
    CLog::Debug("main begin.");
    /*
    while (FCGI_Accept() >= 0)
        printf("Content-type: text/html\r\n"
        "\r\n"
        "<title>FastCGI Hello!</title>"
        "<h1>FastCGI Hello!</h1>"
        "Request number %d running on host <i>%s</i>\n",
        ++count, getenv("SERVER_NAME"));
    */
    fcgi_work(count);
    CLog::Debug("main end.");
    return 0;
}

void fcgi_work(int count)
{
    CLog::Debug("fcgi_work begin");
    int rc = 0;
    string log_info = "";

    if(FCGX_Init()==-1)  
    {  
        CLog::Debug("Init error!");  
        return ;  
    }   
    CLog::Debug("Init ok.");

    HttpRequest httprequest;
    while(1){
        rc = FCGX_Accept_r(&(httprequest.fcgi_request));
        if(rc >= 0){
            CLog::Debug("FCGX_Accept_r return: new http request.");
            CLog::Debug("FCGX_Accept_r end.");
            log_info += "FCGX_Accept_r return: new http request.<br>";
            log_info += "FCGX_Accept_r end.<br>";
            //out buf
            char outbuf[10240];
            char* server_name = FCGX_GetParam("SERVER_NAME", httprequest.fcgi_request.envp);
            sprintf(outbuf, "Content-type: text/html\r\n"
                            "\r\n"
                            "<title>FastCGI Hello!</title>"
                            "<h1>FastCGI Hello!</h1>"
                            "Request number %d running on host <i>%s</i>\n",
                            ++count, server_name);
            //get http request info
            httprequest.GetHttpRequest(&(httprequest));
            string httpreqinfo = httprequest.GetHttpReqInfo();
            CLog::Debug("Http Request Info:" + httpreqinfo);
            //show html info  
            FCGX_Stream* fcgi_out = httprequest.fcgi_request.out;  
            string output(outbuf);  
            //FCGX_PutS(output.c_str(), fcgi_out);
            FCGX_PutStr(output.c_str(), output.length(), fcgi_out);
        }else{
            CLog::Debug("FCGX_Accept_r error. rc=" + transToString(rc));
            log_info += "FCGX_Accept_r error: rc=" + transToString(rc) + string("<br>");
            sleep(1);
            break;
        }
        //finish
        FCGX_Finish_r(&(httprequest.fcgi_request)); 
    }
    CLog::Debug("fcgi_work end");
    return ;
}

common.h和common.cpp

//common.h
#ifndef COMMON_H
#define COMMON_H

#include <sstream>
#include <string.h>

template<typename T>
static std::string transToString(const T &input)
{
    std::stringstream ss;
    std::string output;
    ss<<input;
    ss>>output;
    return output;
}

#endif //COMMON_H
//common.cpp
#include "common.h"

log.h和log.cpp

//log.h
#ifndef __LOG_H__
#define __LOG_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string>
#include <cstring>
#include <sys/time.h>

enum eLogLevel {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL
};

class CLog
{
public:
    CLog();
    ~CLog();

private:
    FILE *m_fp;
    eLogLevel e_cur_level;
    char m_file_name[256];
    void set_level(int level);
    bool write_log(int level, const std::string& str_log);

public:
    bool init(const char* file_name);

    static CLog* g_log;
    static void InitLog();
    //static std::string GetLogLevelName(int nlevel);
    static int GetLogLevel(std::string str_level);
    static void LogInfo(int nLogLevel, const std::string& strLog);
    static void Debug(std::string str_info);
    static void Error(std::string str_info);
};

#endif //__LOG_H__
//log.cpp
#include <unistd.h>

#include "log.h"

CLog* CLog::g_log;

CLog::CLog()
{
    m_fp = NULL;
    memset(m_file_name, 0, 256);
}

CLog::~CLog()
{
    if(m_fp != NULL) {
        fclose(m_fp);
        m_fp = NULL;
    }
}

void CLog::set_level(int level)
{
    e_cur_level = (eLogLevel)level;
}

bool CLog::write_log(int level, const std::string& str_log)
{
    if ((level < e_cur_level) || (NULL == m_fp))
        return false;
    ///
    struct timeval now = {0, 0};
    gettimeofday(&now, NULL);
    time_t t = now.tv_sec;
    struct tm my_tm = *localtime(&t);
    char s[16] = {0};
    switch(level) {
    case 0 :
        strcpy(s, "TRACE");
        break;
    case 1 :
        strcpy(s, "DEBUG");
        break;
    case 2 :
        strcpy(s, "INFO");
        break;
    case 3 :
        strcpy(s, "WARN");
        break;
    case 4 :
        strcpy(s, "ERROR");
        break;
    case 5 :
        strcpy(s, "FATAL");
        break;
    default:
        strcpy(s, "INFO");
        break;
    }
    char buf[204800] = {0};
    std::string log_str;
    sprintf(buf, "%d-%02d-%02d %02d:%02d:%02d.%03ld %s %s\n",
                       my_tm.tm_year + 1900, my_tm.tm_mon + 1, my_tm.tm_mday,
                       my_tm.tm_hour, my_tm.tm_min, my_tm.tm_sec, now.tv_usec, s, str_log.c_str());
    log_str.clear();
    log_str = (std::string)buf;

    pwrite(fileno(m_fp), log_str.c_str(), log_str.size(), 0);

    return true;    
}

bool CLog::init(const char* file_name)
{
    std::string strlog;
    bool bres = false;
    FILE *m_old_fp = m_fp;               // 用m_old_fp来备份,在fopen之后再close,做到新旧文件句柄无缝切换   
    ///
    int n_len = strlen(file_name);
    memcpy(m_file_name, file_name, std::min(n_len, 256));
    m_fp = fopen(file_name, "a");
    if(m_fp == NULL) {
        printf("CLog::init fail, file_name=%s, m_fp=%p\n", file_name, m_fp);
        bres = false;
        exit(-1);                       // log初始化失败,不能启动程序
    } else {
        bres = true;
        // printf("CLog::init OK: %s, fd: %d, pid:%d\n", file_name, fileno(m_fp), getpid());
        if(m_old_fp != NULL) {
            fclose(m_old_fp);
        }
    }
    return bres;    
}

void CLog::InitLog()
{
    std::string str_pathname = "./log/log";
    g_log = new CLog();
    g_log->init(str_pathname.c_str());
    g_log->set_level(DEBUG);
}
/*
static std::string CLog::GetLogLevelName(int nlevel)
{
    switch (nlevel) {
    case    TRACE:
        return "TRACE";
    case    DEBUG:
        return "DEBUG";
    case    INFO:
        return "INFO";
    case    WARN:
        return "WARN";
    case    ERROR:
        return "ERROR";
    case    FATAL:
        return "FATAL";
    default:
        printf("CLog::GetLogLevelName input wrong log level.\n");
        assert(0);
    }   
}*/

void CLog::LogInfo(int nLogLevel, const std::string& strLog)
{
    if (NULL == g_log) return;
    g_log->write_log(nLogLevel, strLog);    
}

void CLog::Debug(std::string str_info)
{
    LogInfo(DEBUG, str_info);
}

void CLog::Error(std::string str_info)
{
    LogInfo(ERROR, str_info);
}

httpscode.hpp:

//httpscode.hpp
#ifndef HTTP_CODE
#define HTTP_CODE
#include <string.h>
#include <string>
#include <stdlib.h>
#include <unistd.h>
#include "fcgio.h"
#include "fcgi_stdio.h"


class ItemReq{
public:
    ItemReq(){
        httpReqMethod = "";
        httpContentType = "";
        httpContentLength = 0;
        queryString = "";
        requestUri = "";
        serverName = "";
        requestScheme = "";
    }
    ~ItemReq(){

    }
public:
    std::string httpReqMethod;          // HTTP请求的方法(get、post等)
    std::string httpContentType;        // HTTP请求头中Content-Type
    int         httpContentLength;      // HTTP请求头中Content-Length
    std::string queryString;            // query_string
    std::string serverName;             // SERVER_NAME
    std::string requestUri;             // REQUEST_URI
    std::string requestScheme;          // REQUEST_SCHEME
    std::string httpReqBody;            // HTTP body

    std::string PrintInfo();
};

class HttpRequest{
public:
    HttpRequest(){
        FCGX_InitRequest(&fcgi_request, 0, 0);
    }
    ~HttpRequest(){

    }
    FCGX_Request fcgi_request;

    int GetHttpRequest(HttpRequest *httprequest);
    std::string GetHttpReqInfo();
public:
    ItemReq m_item_req;
};

#endif //HTTP_CODE
//httpscode.hpp
#include "httpscode.hpp"
#include "common.h"
#include "log.h"

using namespace std;

std::string ItemReq::PrintInfo()
{
    char buf[10240] = {0};
    sprintf(buf, "\n\t requestScheme: %s \
                  \n\t httpReqMethod: %s \
                  \n\t httpContentLength:%d \
                  \n\t httpContentType:%s \
                  \n\t serverName:%s \
                  \n\t requestUri: %s \
                  \n\t httpReqBody: %s.",
                  requestScheme.c_str(),
                  httpReqMethod.c_str(),
                  httpContentLength,
                  httpContentType.c_str(),
                  serverName.c_str(),
                  requestUri.c_str(),
                  httpReqBody.c_str());
    return std::string(buf);
}

std::string HttpRequest::GetHttpReqInfo()
{
    return m_item_req.PrintInfo();
}

int HttpRequest::GetHttpRequest(HttpRequest *httprequest)
{
    char *arg_para;
    FCGX_Request *fcgireq = &(httprequest->fcgi_request);
    HttpRequest *httpreq = httprequest;

    arg_para = FCGX_GetParam("REQUEST_METHOD", fcgireq->envp);
    if (NULL != arg_para && strlen(arg_para) > 0) {
        CLog::Debug("REQUEST_METHOD:" + std::string(arg_para));
        httpreq->m_item_req.httpReqMethod.assign(arg_para);
    }

    arg_para = FCGX_GetParam("CONTENT_LENGTH", fcgireq->envp);
    if (NULL != arg_para && strlen(arg_para) > 0) {
        CLog::Debug("CONTENT_LENGTH:" + std::string(arg_para));
        httpreq->m_item_req.httpContentLength = atoi(arg_para);
    }

    arg_para = FCGX_GetParam("CONTENT_TYPE", fcgireq->envp);
    if (NULL != arg_para && strlen(arg_para) > 0) {
        CLog::Debug("CONTENT_TYPE:" + std::string(arg_para));
        httpreq->m_item_req.httpContentType.assign(arg_para);
    }   

    arg_para = FCGX_GetParam("REQUEST_BODY", fcgireq->envp);
    if (NULL != arg_para && strlen(arg_para) > 0) {
        CLog::Debug("REQUEST_BODY:" + std::string(arg_para));
        httpreq->m_item_req.httpReqBody.assign(arg_para, httpreq->m_item_req.httpContentLength);
    }

    arg_para = FCGX_GetParam("SERVER_NAME", fcgireq->envp);
    if (NULL != arg_para && strlen(arg_para) > 0) {
        CLog::Debug("SERVER_NAME:" + std::string(arg_para));
        httpreq->m_item_req.serverName.assign(arg_para);
    }

    arg_para = FCGX_GetParam("REQUEST_URI", fcgireq->envp);
    if (NULL != arg_para && strlen(arg_para) > 0) {
        CLog::Debug("REQUEST_URI:" + std::string(arg_para));
        httpreq->m_item_req.requestUri.assign(arg_para);
    }

    arg_para = FCGX_GetParam("REQUEST_SCHEME", fcgireq->envp);
    if (NULL != arg_para && strlen(arg_para) > 0) {
        CLog::Debug("REQUEST_SCHEME:" + std::string(arg_para));
        httpreq->m_item_req.requestScheme.assign(arg_para);
    }
    return 0;
}

Makfile文件:

#Makefile
OBJECT=common.o log.o httpscode.o fastcgidemo.o

CPP=g++ -g -fpermissive

INDEBUG=
LIBFLAG=-lfcgi

all: fastcgi

$(OBJECT):%.o:%.cpp
    $(CPP)  -I. ${INDEBUG} ${LIBFLAG} -c $< -o $@

fastcgi:$(OBJECT)
    $(CPP) -o fastcgi ${OBJECT} ${INDEBUG} ${LIBFLAG} 
clean:
    $(RM) *.o fastcgi

Start.sh

#start
BIND_IP=192.168.37.131
BIND_PORT=8828

echo "/usr/local/bin/spawn-fcgi -a ${BIND_IP} -p ${BIND_PORT} -F 1  ./fastcgi;"
/usr/local/bin/spawn-fcgi -a ${BIND_IP} -p ${BIND_PORT} -F 1  ./fastcgi;

猜你喜欢

转载自blog.csdn.net/feng973/article/details/80184418