项目简介:
基于 HTTP 协议实现一个多线程服务器,客户端通过浏览器发送请求,服务器接收并分析客户端的请求方法和资源,从而执行相应的逻辑处理,最终将客户请求的资源以 HTML 页面的形式呈现,并能进行差错处理。
项目思路:
首先实现两个主机不同进程间的通信,当服务器收到请求后,要进行分析请求方法,当方法确定后应该拿到请求的资源,接下来要根据资源是否存在执行相应的逻辑处理。GET 方法:如果没有参数,进入非 cgi 模式运行;否则,进入 cgi 模式运行;只要是 POST 方法就一定要支持 cgi:直接进入
cgi 模式运行。
项目特点:
1、支持客户端/服务器模式,客户端能够使用 GET、POST 方法请求资源;
2、简单快速:客户向服务器请求服务时,只需传送请求方法和路径;
3、灵活:HTTP 允许传输任意类型的数据对象,正在传输的类型由 Content-Type 加以标记。
项目所包含目录:
sql_connect
wwwroot
lib
http.c代码
1 #include<stdio.h>
2 #include<string.h>
3 #include<unistd.h>
4 #include<fcntl.h>
5 #include<stdlib.h>
6 #include<ctype.h>
7 #include<sys/stat.h>
8 #include<sys/socket.h>
9 #include<netinet/in.h>
10 #include<arpa/inet.h>
11 #include<sys/sendfile.h>
12 #include<pthread.h>
13
14 #define MAX 1024
15 #define HOME_PAGE "index.html"
16 #define PAGE_404 "wwwroot/404.html"
17
18 static void usage(const char *proc)
19 {
20 printf("Usage:%s [port]\n",proc);
21 }
22
23 static int startup(int port)
24 {
25 int sock = socket(AF_INET,SOCK_STREAM,0);
26 if(sock < 0){
27 perror("socket");
28 exit(2);
29 }
30
31 int opt = 1;
32 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
33
34 struct sockaddr_in local;
35 local.sin_family = AF_INET;
36 local.sin_addr.s_addr = htonl(INADDR_ANY);
37 local.sin_port = htons(port);
38
39 if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0){
40 perror("bind");
41 exit(3);
42 }
43
44 if(listen(sock,5) < 0){
45 perror("listen");
46 exit(4);
47 }
48
49 return sock;
50 }
51
52 static int getLine(int sock,char line[],int size)
53 {
54 //\r,\r\n,\n -> \n
55 char c = 'a';
56 int i = 0;
57 while(c != '\n' && i < size - 1){
58 ssize_t s = recv(sock,&c,1,0);
59 if(c == '\r'){
60 recv(sock,&c,1,MSG_PEEK);
61 if(c== '\n'){
62 recv(sock,&c,1,0);
63 }else{
64 c = '\n';
65 }
66 }
67 line[i++] = c;
68 }
69 line[i] = '\0';
70 return i;
71 }
72
73 static void clearHeader(int sock)
74 {
75 char line[MAX];
76 do{
77 getLine(sock,line,sizeof(line));
78 }while(strcmp("\n",line));
79 }
80
81 void show_404(int sock)
82 {
83 char line[MAX];
84 struct stat st;
85 sprintf(line,"HTTP/1.0 404 NOT FOUND\r\n");
86 send(sock,line,strlen(line),0);
87 sprintf(line,"Content-Type:text/html:charset=ISO-8859-1\r\n");
88 send(sock,line,strlen(line),0);
89 sprintf(line,"\r\n");
90 send(sock,line,strlen(line),0);
91 int fd = open(PAGE_404,O_RDONLY);
92 stat(PAGE_404,&st);
93 sendfile(sock,fd,NULL,st.st_size);
94 close(fd);
95 }
96
97 static void echoErrMsg(int sock,int status_code)
98 {
99 switch(status_code){
100 case 301:
101 break;
102 case 302:
103 break;
104 case 307:
105 break;
106 case 400:
107 break;
108 case 403:
109 break;
110 case 404:
111 show_404(sock);
112 break;
113 case 500:
114 break;
115 case 503:
116 break;
117 default:
118 break;
119 }
120 }
121
122 int exe_cgi(int sock,char *method,char *path,char *query_string)
123 {
124 char line[MAX];
125 int content_length = -1;
126 char method_env[MAX/32];
127 char query_string_env[MAX];
128 char content_length_env[MAX/8];
129
130 if(strcasecmp(method,"GET") == 0){
131 clearHeader(sock);
132 }else{ //POST
133 do{
134 getLine(sock,line,sizeof(line));
135 if(strncasecmp(line,"Content-Length: ",16) == 0){
136 content_length = atoi(line + 16);
137 }
138 }while(strcmp(line,"\n"));
139 if(content_length == -1){
140 return 400;
141 }
142 }
143
144 int input[2];
145 int output[2];
146
147 pipe(input);
148 pipe(output);
149
150 pid_t id = fork();
151 if(id < 0){
152 return 500;
153 }
154 else if(id == 0){ //child
155 close(input[1]);
156