[PHP] 通用网关接口CGI 的运行原理详解编程语言

CGI 的运行原理:
1.客户端访问某个 URL 地址之后,通过 GET/POST/PUT 等方式提交数据,并通过 HTTP 协议向 Web 服务器发出请求。
2.服务器端的 HTTP Daemon(守护进程)启动一个子进程。然后在子进程中,将 HTTP 请求里描述的信息通过标准输入 stdin 和环境变量传递给 URL 指定的 CGI 程序,并启动此应用程序进行处理,处理结果通过标准输出 stdout 返回给 HTTP Daemon 子进程。
再由 HTTP Daemon 子进程通过 HTTP 协议返回给客户端。

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.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);             // /user?id=1  
filename = strtok(p, "?");           // /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; 
}

user.c

#include <stdio.h> 
#include <stdlib.h> 
// 通过获取的 id 查询用户的信息 
int main(void) { 
//============================ 模拟数据库 ============================ 
typedef struct { 
int id; 
char *username; 
int age; 
} user; 
user users[] = { 
{}, 
{ 
1, 
"taoshihan", 
10 
} 
}; 
//============================ 模拟数据库 ============================ 
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; 
}

 

 

访问文件流(stream I/O)的方式进行网络数据传输
1.fdopen:打开一个标准的IO流
原型:FILE *fdopen(int fd, const char *type);
fd是用open函数得到文件描述符,type是打开模式

2.setbuf:定义流 stream 应如何缓冲
原型:void setbuf(FILE *stream, char *buffer)

3.fgets:从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内,如果成功,该函数返回相同的 str 参数。
原型:char *fgets(char *str, int n, FILE *stream)

处理并传递参数
4.strtok:分解字符串 str 为一组字符串,delim 为分隔符。
原型:char *strtok(char *str, const char *delim)

5.putenv setenv getenv获取设置环境变量相关函数
头文件:#include4<stdlib.h>
putenv(“PATH=/shihan”);
char *v=getenv(“PATH”);
printf(“%s/n”,v);

拼接字符串
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;
}
malloc:分配所需的内存空间,并返回一个指向它的指针。
原型:void *malloc(size_t size)

strcpy:把 src 所指向的字符串复制到 dest。
原型:char *strcpy(char *dest, const char *src)

strcat:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
char *strcat(char *dest, const char *src)

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/12508.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论