欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Nginx和FastCGI学习之一

程序员文章站 2024-02-21 15:14:52
...

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 [email protected]

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;
相关标签: nginx fastCGI