#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#define SERV_PORT 9003
char *str_join(char *str1, char *str2);
char *html_response(char *res, char *buf);
int main(void) {
int lfd, cfd;
struct sockaddr_in serv_addr, clin_addr;
socklen_t clin_len;
char buf[1024], web_result[1024];
int len;
FILE *cin;
if ((lfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("create socket failed");
exit(1);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_PORT);
if (bind(lfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1) {
perror("bind error");
exit(1);
}
if (listen(lfd, 128) == -1) {
perror("listen error");
exit(1);
}
signal(SIGCLD, SIG_IGN);
while (1) {
clin_len = sizeof(clin_addr);
if ((cfd = accept(lfd, (struct sockaddr *) &clin_addr, &clin_len)) == -1) {
perror("接收错误\n");
continue;
}
cin = fdopen(cfd, "r");
setbuf(cin, (char *) 0);
fgets(buf, 1024, cin); //读取第一行
printf("\n%s", buf);
//============================ cgi 环境变量设置演示 ============================
// 例如 "GET /cgi-bin/user?id=1 HTTP/1.1";
char *delim = " ";
char *p;
char *method, *filename, *query_string;
char *query_string_pre = "QUERY_STRING=";
method = strtok(buf, delim); // GET
p = strtok(NULL, delim); // /cgi-bin/user?id=1
filename = strtok(p, "?"); // /cgi-bin/user
if (strcmp(filename, "/favicon.ico") == 0) {
continue;
}
query_string = strtok(NULL, "?"); // id=1
putenv(str_join(query_string_pre, query_string));
//============================ cgi 环境变量设置演示 ============================
int pid = fork();
if (pid > 0) {
close(cfd);
}
else if (pid == 0) {
close(lfd);
FILE *stream = popen(str_join(".", filename), "r");
fread(buf, sizeof(char), sizeof(buf), stream);
html_response(web_result, buf);
write(cfd, web_result, sizeof(web_result));
pclose(stream);
close(cfd);
exit(0);
}
else {
perror("fork error");
exit(1);
}
}
close(lfd);
return 0;
}
char *str_join(char *str1, char *str2) {
char *result = malloc(strlen(str1) + strlen(str2) + 1);
if (result == NULL) exit(1);
strcpy(result, str1);
strcat(result, str2);
return result;
}
char *html_response(char *res, char *buf) {
char *html_response_template = "HTTP/1.1 200 OK\r\nContent-Type:text/html\r\nContent-Length: %d\r\nServer: mengkang\r\n\r\n%s";
sprintf(res, html_response_template, strlen(buf), buf);
return res;
}
#include <stdio.h>
#include <stdlib.h>
// 通过获取的 id 查询用户的信息
int main(void) {
//============================ 模拟数据库 ============================
typedef struct {
int id;
char *username;
int age;
} user;
user users[] = {
{},
{
1,
"mengkang.zhou",
18
}
};
//============================ 模拟数据库 ============================
char *query_string;
int id;
query_string = getenv("QUERY_STRING");
if (query_string == NULL) {
printf("没有输入数据");
} else if (sscanf(query_string, "id=%d", &id) != 1) {
printf("没有输入id");
} else {
printf("用户信息查询<br>学号: %d<br>姓名: %s<br>年龄: %d", id, users[id].username, users[id].age);
}
return 0;
}
typedef enum _fcgi_request_type {
FCGI_BEGIN_REQUEST = 1, /* [in] */
FCGI_ABORT_REQUEST = 2, /* [in] (not supported) */
FCGI_END_REQUEST = 3, /* [out] */
FCGI_PARAMS = 4, /* [in] environment variables */
FCGI_STDIN = 5, /* [in] post data */
FCGI_STDOUT = 6, /* [out] response */
FCGI_STDERR = 7, /* [out] errors */
FCGI_DATA = 8, /* [in] filter data (not supported) */
FCGI_GET_VALUES = 9, /* [in] */
FCGI_GET_VALUES_RESULT = 10 /* [out] */
} fcgi_request_type;
typedef struct _fcgi_header {
unsigned char version;
unsigned char type;
unsigned char requestIdB1;
unsigned char requestIdB0;
unsigned char contentLengthB1;
unsigned char contentLengthB0;
unsigned char paddingLength;
unsigned char reserved;
} fcgi_header;
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main()
{
unsigned char requestIdB1 = UCHAR_MAX;
unsigned char requestIdB0 = UCHAR_MAX;
printf("%d\n", (requestIdB1 << 8) + requestIdB0); // 65535
}
FCGI_REQUEST_COMPLETE:请求的正常结束。
FCGI_CANT_MPX_CONN:拒绝新请求。这发生在Web服务器通过一条线路向应用发送并发的请求时,后者被设计为每条线路每次处理一个请求。
FCGI_OVERLOADED:拒绝新请求。这发生在应用用完某些资源时,例如数据库连接。
FCGI_UNKNOWN_ROLE:拒绝新请求。这发生在Web服务器指定了一个应用不能识别的角色时。
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
while (parent) {
do {
pid = fork(); // 生成新的子进程
switch (pid) {
case 0: // 子进程
parent = 0;
/* don't catch our signals */
sigaction(SIGTERM, &old_term, 0); // 终止信号
sigaction(SIGQUIT, &old_quit, 0); // 终端退出符
sigaction(SIGINT, &old_int, 0); // 终端中断符
break;
...
default:
/* Fine */
running++;
break;
} while (parent && (running < children));
...
while (!fastcgi || fcgi_accept_request(&request) >= 0) {
SG(server_context) = (void *) &request;
init_request_info(TSRMLS_C);
CG(interactive) = 0;
...
}
/* {{{ sapi_module_struct cgi_sapi_module
*/
static sapi_module_struct cgi_sapi_module = {
"cgi-fcgi", /* name */
"CGI/FastCGI", /* pretty name */
php_cgi_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
sapi_cgi_activate, /* activate */
sapi_cgi_deactivate, /* deactivate */
sapi_cgibin_ub_write, /* unbuffered write */
sapi_cgibin_flush, /* flush */
NULL, /* get uid */
sapi_cgibin_getenv, /* getenv */
php_error, /* error handler */
NULL, /* header handler */
sapi_cgi_send_headers, /* send headers handler */
NULL, /* send header handler */
sapi_cgi_read_post, /* read POST data */
sapi_cgi_read_cookies, /* read Cookies */
sapi_cgi_register_variables, /* register server variables */
sapi_cgi_log_message, /* Log message */
NULL, /* Get request time */
NULL, /* Child terminate */
STANDARD_SAPI_MODULE_PROPERTIES
};
/* }}} */
http://www.fastcgi.com/drupal/node/2
http://baike.baidu.com/view/641394.htm
http://www.php-internals.com/book/?p=chapt02/02-02-03-fastcgi