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;
推荐阅读
-
Golang中 怎么通过sock实现Nginx和golang程序的fastcgi通讯
-
Nginx和FastCGI学习之一
-
Nginx与PHP(FastCGI)的安装、配置和优化
-
nginx学习记录--安装和转发到tomcat
-
Linux学习系列之一:在centos 7.5上安装nginx 以及简单配置
-
nginx 源码学习笔记(十三)——文件读写和配置文件读取
-
在Mac OS上部署Nginx和FastCGI以及Flask框架的教程
-
Android ABC Jetpack学习之一文学会Navigation(附源码解析和使用封装)
-
运行《神经网络和深度学习》中程序遇到的问题之一,xrange错误
-
nginx 学习笔记_nginx 安装和启动