-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy path15-2pool_cgi.cpp
160 lines (144 loc) · 4.4 KB
/
15-2pool_cgi.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include "15-1processpool.h"
/* 用于处理客户CGI请求的类, 它可以作为processpool类的模板参数 */
class cgi_conn
{
public:
cgi_conn() {}
~cgi_conn() {}
/* 初始化客户连接,清空读缓冲区 */
void init(int epollfd, int sockfd, const sockaddr_in &client_addr)
{
m_epollfd = epollfd;
m_sockfd = sockfd;
m_address = client_addr;
memset(m_buf, '\0', BUFFER_SIZE);
m_read_idx = 0;
}
void process()
{
int idx = 0;
int ret = -1;
/* 循环读取和分析客户数据 */
while (true)
{
idx = m_read_idx;
ret = recv(m_sockfd, m_buf + idx, BUFFER_SIZE - 1 - idx, 0);
/* 如果读操作发生错误,则关闭客户连接。但如果是暂时无数据可读,则退出循环 */
if (ret < 0)
{
if (errno != EAGAIN)
{
removefd(m_epollfd, m_sockfd);
}
break;
}
/* 如果对方关闭连接,则服务器也关闭连接 */
else if (ret == 0)
{
removefd(m_epollfd, m_sockfd);
break;
}
else
{
m_read_idx += ret;
printf("user content is %s\n", m_buf);
/* 如果遇到字符"\r\n",则开始处理客户请求 */
for (; idx < m_read_idx; ++idx)
{
if ((idx >= 1) && (m_buf[idx - 1] == '\r') && (m_buf[idx] == '\n'))
{
break;
}
}
/* 如果没有遇到字符"\r\n", 则需要读取更多客户数据 */
if (idx == m_read_idx)
{
continue;
}
m_buf[idx - 1] = '\0';
char *file_name = m_buf;
/* 判断客户要运行的cgi程序是否存在 */
if (access(file_name, F_OK) == -1)
{
removefd(m_epollfd, m_sockfd);
break;
}
/* 创建子进程来执行CGI程序 */
ret = fork();
if (ret == -1)
{
removefd(m_epollfd, m_sockfd);
break;
}
else if (ret > 0)
{
/* 父进程只需要关闭连接 */
removefd(m_epollfd, m_sockfd);
break;
}
else
{
/* 子进程将标准输出定制到 m_sockfd, 并执行CGI程序 */
close(STDOUT_FILENO);
dup(m_sockfd);
execl(m_buf, m_buf, NULL);
exit(0);
}
}
}
}
private:
/* 读缓冲区的大小 */
static const int BUFFER_SIZE = 1024;
static int m_epollfd;
int m_sockfd;
sockaddr_in m_address;
char m_buf[BUFFER_SIZE];
/* 标记读缓冲区已经读入客户数据的最后一个字节的下一个位置 */
int m_read_idx;
};
int cgi_conn::m_epollfd = -1;
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("usage: %s ip_address port_number\n", basename(argv[0]));
return 1;
}
const char *ip = argv[1];
int port = atoi(argv[2]);
int listenfd = socket(PF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
int ret = 0;
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
assert(ret != -1);
ret = listen(listenfd, 5);
assert(ret != -1);
processpool<cgi_conn> *pool = processpool<cgi_conn>::create(listenfd);
if (pool)
{
pool->run();
delete pool;
}
close(listenfd); /* main函数创建了文件描述符listenfd,那么就由它亲自关闭 */
return 0;
}