tinyhttpd-0.1.0_hacking
生活随笔
收集整理的這篇文章主要介紹了
tinyhttpd-0.1.0_hacking
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
1 /****************************************************************************
2 *
3 * tinyhttpd-0.1.0_hacking
4 *
5 * 1.這是tinyhttpd-0.1.0版本中httpd.c(主程序)的源碼,源碼不到500行(除去注釋).
6 * 2.通過分析、閱讀該源碼,可以一窺web服務(wù)器的大致工作機(jī)制.
7 * 3.知識(shí)量:
8 * 1.C語言;
9 * 2.Unix或類Unix系統(tǒng)編程;
10 * 3.微量的http協(xié)議(請(qǐng)求行、消息頭、實(shí)體內(nèi)容);
11 * 4.如何閱讀別人的代碼( 從main函數(shù)開始 :) );
12 * 4.tinyhttpd-0.1.0 文件結(jié)構(gòu)如下:
13 * .
14 * |-- Makefile -------->makefile 文件
15 * |-- README -------->說明文檔
16 * |-- htdocs -------->程序會(huì)到該文件夾下找對(duì)應(yīng)html、cgi文件
17 * | |-- README -------->說明文檔
18 * | |-- check.cgi -------->cgi 程序
19 * | |-- color.cgi ----^
20 * | `-- index.html -------->默認(rèn)的 web 首頁文件
21 * |-- httpd.c -------->你接下來要閱讀的文件
22 * `-- simpleclient.c -------->沒發(fā)現(xiàn)該文件有任何用處 @_@
23 * 5.如何閱讀該文檔:
24 * 1.linux下使用vi/vim配和ctags,windows下使用Source Insight,當(dāng)然你也
25 * 可以用其他文本編輯器看.
26 * 2.先找到main函數(shù),然后就可以開始閱讀了,遇到對(duì)應(yīng)的函數(shù),就去看對(duì)應(yīng)的
27 * 函數(shù).
28 * 3.對(duì)于有些函數(shù),本人沒有添加注釋,或者說本人覺得沒必要.
29 * 4.祝您好運(yùn). :)
30 *
31 * 6.tinyhttpd-0.1.0版本下載url: http://sourceforge.net/projects/tinyhttpd/
32 *
33 * 如果您對(duì)本文有任何意見、提議,可以發(fā)郵件至zengjf42@163.com,會(huì)盡快回復(fù).
34 * 本文的最終解釋權(quán)歸本人(曾劍鋒)所有,僅供學(xué)習(xí)、討論.
35 *
36 * 2015-3-1 陰 深圳 尚觀 Var
37 *
38 ***************************************************************************/
39
40
41 /* J. David's webserver */
42 /* This is a simple webserver.
43 * Created November 1999 by J. David Blackstone.
44 * CSE 4344 (Network concepts), Prof. Zeigler
45 * University of Texas at Arlington
46 */
47 /* This program compiles for Sparc Solaris 2.6.
48 * To compile for Linux:
49 * 1) Comment out the #include <pthread.h> line.
50 * 2) Comment out the line that defines the variable newthread.
51 * 3) Comment out the two lines that run pthread_create().
52 * 4) Uncomment the line that runs accept_request().
53 * 5) Remove -lsocket from the Makefile.
54 */
55 #include <stdio.h>
56 #include <sys/socket.h>
57 #include <sys/types.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <unistd.h>
61 #include <ctype.h>
62 #include <strings.h>
63 #include <string.h>
64 #include <sys/stat.h>
65 #include <pthread.h>
66 #include <sys/wait.h>
67 #include <stdlib.h>
68
69 #define ISspace(x) isspace((int)(x))
70
71 #define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n"
72
73 void accept_request(int);
74 void bad_request(int);
75 void cat(int, FILE *);
76 void cannot_execute(int);
77 void error_die(const char *);
78 void execute_cgi(int, const char *, const char *, const char *);
79 int get_line(int, char *, int);
80 void headers(int, const char *);
81 void not_found(int);
82 void serve_file(int, const char *);
83 int startup(u_short *);
84 void unimplemented(int);
85
86 /**
87 * accept_request 函數(shù)說明:
88 * 1.獲取請(qǐng)求方式,目前只支持GET、POST請(qǐng)求;
89 * 2.在本程序中所有的POST請(qǐng)求、帶參數(shù)的GET請(qǐng)求都都被定義為訪問cgi程序;
90 * 3.從帶參數(shù)的GET請(qǐng)求中分離出請(qǐng)求參數(shù);
91 * 4.如果沒有指定需要訪問的文件,使用index.html文件作為默認(rèn)訪問文件;
92 * 5.檢查需要訪問的文件是否存在,以及其是否具有對(duì)應(yīng)的權(quán)限;
93 * 6.根據(jù)是否是cgi程序訪問,來執(zhí)行對(duì)應(yīng)的任務(wù).
94 */
95 void accept_request(int client)
96 {
97 /**
98 * 局部變量說明:
99 * 1.buf : buffer縮寫,主要用于暫存從socket中讀出來的數(shù)據(jù);
100 * 2.numchars : 用于保存每次從socket中讀到的字符的個(gè)數(shù);
101 * 3.method : 用于保存請(qǐng)求方式,目前該軟件只支持GET、POST這兩種方式;
102 * 4.url : 用于保存訪問文件信息,有些地方叫uri;
103 * 5.path : 用于保存文件路徑;
104 * 6.i, j : 處理數(shù)據(jù)時(shí)的下標(biāo);
105 * 7.st : 在判斷文件類型、是否存在的時(shí)候用到;
106 * 8.cgi : 是否調(diào)用cgi程序的標(biāo)志.
107 */
108 char buf[1024];
109 int numchars;
110 char method[255];
111 char url[255];
112 char path[512];
113 size_t i, j;
114 struct stat st;
115 int cgi = 0; /* becomes true if server decides this is a CGI
116 * program */
117 char *query_string = NULL;
118
119 /**
120 * 判斷程序是否是GET、POST請(qǐng)求兩種的其中一種,如果不是則報(bào)錯(cuò).
121 */
122 numchars = get_line(client, buf, sizeof(buf));
123 i = 0; j = 0;
124 while (!ISspace(buf[j]) && (i < sizeof(method) - 1))
125 {
126 method[i] = buf[j];
127 i++; j++;
128 }
129 method[i] = '\0';
130
131 if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
132 {
133 unimplemented(client);
134 return;
135 }
136
137 /**
138 * 該程序把POST請(qǐng)求定義為cgi請(qǐng)求.
139 */
140 if (strcasecmp(method, "POST") == 0)
141 cgi = 1;
142
143 /**
144 * 獲取當(dāng)前url,這里的url不過括網(wǎng)址,而是除去網(wǎng)址之后的東西,
145 * 如瀏覽器中輸入:http://127.0.0.1:8080/example/index.html
146 * 得到的url:/example/index.html
147 * 在有些地方不稱這個(gè)為url,稱之為uri
148 */
149 i = 0;
150 while (ISspace(buf[j]) && (j < sizeof(buf)))
151 j++;
152 while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf)))
153 {
154 url[i] = buf[j];
155 i++; j++;
156 }
157 url[i] = '\0';
158
159 /**
160 * 每次運(yùn)行的時(shí)候都會(huì)出現(xiàn)2次這個(gè),目前還不知道是什么原因?qū)е碌脑?
161 * 這是本人在源代碼的基礎(chǔ)上添加的調(diào)試輸出.
162 * url: /favicon.ico
163 * url: /favicon.ico
164 */
165 printf("url: %s\n", url);
166
167 /**
168 * 如果是GET請(qǐng)求,如果帶了請(qǐng)求參數(shù),那么也是cgi請(qǐng)求,并且從url中分離出請(qǐng)求參數(shù)
169 */
170 if (strcasecmp(method, "GET") == 0)
171 {
172 query_string = url;
173 while ((*query_string != '?') && (*query_string != '\0'))
174 query_string++;
175 if (*query_string == '?')
176 {
177 cgi = 1;
178 *query_string = '\0';
179 query_string++;
180 }
181 }
182
183 /**
184 * 所有的需要的html文件、cgi程序都在htdocs文件夾中,
185 * 如果沒有指定html文件,或者cgi程序,那么使用默認(rèn)的index.html文件
186 * 作為目標(biāo)輸出文件.
187 */
188 sprintf(path, "htdocs%s", url);
189 if (path[strlen(path) - 1] == '/')
190 strcat(path, "index.html");
191
192 /**
193 * 檢查要訪問的文件的狀態(tài),如:
194 * 1.是否存在;
195 * 2.是否是一個(gè)文件夾;
196 * 3.如果是cgi程序,是否用于對(duì)應(yīng)的權(quán)限.
197 * 當(dāng)然如果執(zhí)行stat時(shí)就出錯(cuò)了,那么,直接將socket中的數(shù)據(jù)讀完,
198 * 然后返回沒有找到相關(guān)內(nèi)容的信息提示.
199 */
200 if (stat(path, &st) == -1) {
201 while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
202 numchars = get_line(client, buf, sizeof(buf));
203 not_found(client);
204 }
205 else
206 {
207 if ((st.st_mode & S_IFMT) == S_IFDIR) /* 如果是一個(gè)文件夾 */
208 strcat(path, "/index.html");
209 if ((st.st_mode & S_IXUSR) ||
210 (st.st_mode & S_IXGRP) ||
211 (st.st_mode & S_IXOTH) ) /* 權(quán)限問題 */
212 cgi = 1;
213
214 /**
215 * 通過cgi變量來判斷是執(zhí)行cgi程序,還是僅僅是返回一個(gè)html頁面.
216 */
217 if (!cgi)
218 serve_file(client, path); /* 向客戶端返回一個(gè)html文件 */
219 else
220 execute_cgi(client, path, method, query_string); /* 執(zhí)行一個(gè)cgi程序 */
221 }
222
223 close(client);
224 }
225
226 void bad_request(int client)
227 {
228 char buf[1024];
229
230 sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n");
231 send(client, buf, sizeof(buf), 0);
232 sprintf(buf, "Content-type: text/html\r\n");
233 send(client, buf, sizeof(buf), 0);
234 sprintf(buf, "\r\n");
235 send(client, buf, sizeof(buf), 0);
236 sprintf(buf, "<P>Your browser sent a bad request, ");
237 send(client, buf, sizeof(buf), 0);
238 sprintf(buf, "such as a POST without a Content-Length.\r\n");
239 send(client, buf, sizeof(buf), 0);
240 }
241
242 /**
243 * 主要完成將resource指向的文件內(nèi)容拷貝輸出到客戶端瀏覽器中
244 */
245 void cat(int client, FILE *resource)
246 {
247 char buf[1024];
248
249 fgets(buf, sizeof(buf), resource);
250 while (!feof(resource))
251 {
252 send(client, buf, strlen(buf), 0);
253 fgets(buf, sizeof(buf), resource);
254 }
255 }
256
257 void cannot_execute(int client)
258 {
259 char buf[1024];
260
261 sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n");
262 send(client, buf, strlen(buf), 0);
263 sprintf(buf, "Content-type: text/html\r\n");
264 send(client, buf, strlen(buf), 0);
265 sprintf(buf, "\r\n");
266 send(client, buf, strlen(buf), 0);
267 sprintf(buf, "<P>Error prohibited CGI execution.\r\n");
268 send(client, buf, strlen(buf), 0);
269 }
270
271 void error_die(const char *sc)
272 {
273 perror(sc);
274 exit(1);
275 }
276
277 void execute_cgi(int client, const char *path,
278 const char *method, const char *query_string)
279 {
280 /**
281 * 局部變量說明:
282 * 1.buf : buffer縮寫;
283 * 2.cgi_output : 用于保存輸出管道的文件描述符;
284 * 3.cgi_input : 用于保存輸入管道的文件描述符;
285 * 4.pid : 進(jìn)程pid,最后父進(jìn)程退出之前,等待子進(jìn)程先退出,
286 * 并回收相關(guān)的資源,這部分工作主要由waitpid()來完成;
287 * 5.status : 在waitpid()中用于保存子進(jìn)程的退出狀態(tài),本程序沒有具體使用;
288 * 6.i : 計(jì)數(shù)器;
289 * 7.c : POST讀取請(qǐng)求參數(shù)時(shí),讀取到的字符保存在這里;
290 * 8.numchars : 讀取的字符個(gè)數(shù);
291 * 9.conten_length : 內(nèi)容實(shí)體的字符數(shù);
292 */
293 char buf[1024];
294 int cgi_output[2];
295 int cgi_input[2];
296 pid_t pid;
297 int status;
298 int i;
299 char c;
300 int numchars = 1;
301 int content_length = -1;
302
303 /**
304 * 在本程序中,GET請(qǐng)求的消息頭沒有任何用處,直接處理掉就行了,
305 * 而如果是POST請(qǐng)求,需要的消息頭中的獲取實(shí)體的大小,也就是Content-Length:后面跟的數(shù)字
306 */
307 buf[0] = 'A'; buf[1] = '\0';
308 if (strcasecmp(method, "GET") == 0)
309 while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
310 numchars = get_line(client, buf, sizeof(buf));
311 else /* POST */
312 {
313 numchars = get_line(client, buf, sizeof(buf));
314 while ((numchars > 0) && strcmp("\n", buf))
315 {
316 buf[15] = '\0';
317 if (strcasecmp(buf, "Content-Length:") == 0)
318 content_length = atoi(&(buf[16]));
319 numchars = get_line(client, buf, sizeof(buf));
320 }
321 if (content_length == -1) {
322 bad_request(client);
323 return;
324 }
325 }
326
327 /**
328 * 返回返回行信息.
329 */
330 sprintf(buf, "HTTP/1.0 200 OK\r\n");
331 send(client, buf, strlen(buf), 0);
332
333 /**
334 * 父子進(jìn)程通過管道通信.
335 */
336 if (pipe(cgi_output) < 0) {
337 cannot_execute(client);
338 return;
339 }
340 if (pipe(cgi_input) < 0) {
341 cannot_execute(client);
342 return;
343 }
344
345 /**
346 * 創(chuàng)建子進(jìn)程,用于執(zhí)行cgi程序,父進(jìn)程接受子進(jìn)程的結(jié)果,并返回給瀏覽器
347 */
348 if ( (pid = fork()) < 0 ) {
349 cannot_execute(client);
350 return;
351 }
352 if (pid == 0) /* child: CGI script */
353 {
354 char meth_env[255]; //cgi 請(qǐng)求方式環(huán)境變量
355 char query_env[255]; //cgi GET請(qǐng)求參數(shù)環(huán)境變量
356 char length_env[255]; //cgi POST請(qǐng)求參數(shù)內(nèi)容大小環(huán)境變量
357
358 /**
359 * 重定向標(biāo)準(zhǔn)輸入輸出,并設(shè)置好對(duì)應(yīng)的環(huán)境變量.
360 */
361 dup2(cgi_output[1], 1);
362 dup2(cgi_input[0], 0);
363 close(cgi_output[0]);
364 close(cgi_input[1]);
365 sprintf(meth_env, "REQUEST_METHOD=%s", method);
366 putenv(meth_env);
367 if (strcasecmp(method, "GET") == 0) {
368 sprintf(query_env, "QUERY_STRING=%s", query_string);
369 putenv(query_env);
370 }
371 else { /* POST */
372 sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
373 putenv(length_env);
374 }
375 /* 執(zhí)行對(duì)應(yīng)的程序 */
376 execl(path, path, NULL);
377 exit(0);
378 } else { /* parent */
379 close(cgi_output[1]);
380 close(cgi_input[0]);
381 /**
382 * 對(duì)于POST請(qǐng)求,將實(shí)體中的請(qǐng)求參數(shù)通過管道傳送到cgi程序中
383 */
384 if (strcasecmp(method, "POST") == 0)
385 for (i = 0; i < content_length; i++) {
386 recv(client, &c, 1, 0);
387 write(cgi_input[1], &c, 1);
388 }
389 /**
390 * 讀取cgi程序的執(zhí)行結(jié)果,返回給瀏覽器
391 */
392 while (read(cgi_output[0], &c, 1) > 0)
393 send(client, &c, 1, 0);
394
395 close(cgi_output[0]);
396 close(cgi_input[1]);
397 /**
398 * 等待子進(jìn)程運(yùn)行結(jié)束,并回收子進(jìn)程的資源,
399 * 防止出現(xiàn)孤兒進(jìn)程
400 */
401 waitpid(pid, &status, 0);
402 }
403 }
404
405 int get_line(int sock, char *buf, int size)
406 {
407 /**
408 * 局部變量說明:
409 * 1.i : 數(shù)組下標(biāo)計(jì)數(shù),不能大于size;
410 * 2.c : 每次讀到的字符保存在這里面;
411 * 3.n : 每次讀到的字符個(gè)數(shù).
412 */
413 int i = 0;
414 char c = '\0';
415 int n;
416
417 /**
418 * 一直讀到buf滿了,或者遇到了'\n'為止.
419 */
420 while ((i < size - 1) && (c != '\n'))
421 {
422 n = recv(sock, &c, 1, 0);
423 /* DEBUG printf("%02X\n", c); */
424 if (n > 0)
425 {
426 /**
427 * 讀到'\r'也算是結(jié)束,通過判斷后面有沒有跟'\n'來判斷是否要將下
428 * 一個(gè)字符取出來,并且無論'\r'后面跟不跟'\n',都將'\r'換成'\n'.
429 */
430 if (c == '\r')
431 {
432 n = recv(sock, &c, 1, MSG_PEEK);
433 /* DEBUG printf("%02X\n", c); */
434 if ((n > 0) && (c == '\n'))
435 recv(sock, &c, 1, 0);
436 else
437 c = '\n';
438 }
439 buf[i] = c;
440 i++;
441 }
442 else
443 c = '\n';
444 }
445 buf[i] = '\0'; /* 字符串結(jié)尾 */
446
447 return(i);
448 }
449
450 void headers(int client, const char *filename)
451 {
452 char buf[1024];
453 (void)filename; /* could use filename to determine file type */
454
455 strcpy(buf, "HTTP/1.0 200 OK\r\n");
456 send(client, buf, strlen(buf), 0);
457 strcpy(buf, SERVER_STRING);
458 send(client, buf, strlen(buf), 0);
459 sprintf(buf, "Content-Type: text/html\r\n");
460 send(client, buf, strlen(buf), 0);
461 strcpy(buf, "\r\n");
462 send(client, buf, strlen(buf), 0);
463 }
464
465 void not_found(int client)
466 {
467 char buf[1024];
468
469 sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
470 send(client, buf, strlen(buf), 0);
471 sprintf(buf, SERVER_STRING);
472 send(client, buf, strlen(buf), 0);
473 sprintf(buf, "Content-Type: text/html\r\n");
474 send(client, buf, strlen(buf), 0);
475 sprintf(buf, "\r\n");
476 send(client, buf, strlen(buf), 0);
477 sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
478 send(client, buf, strlen(buf), 0);
479 sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
480 send(client, buf, strlen(buf), 0);
481 sprintf(buf, "your request because the resource specified\r\n");
482 send(client, buf, strlen(buf), 0);
483 sprintf(buf, "is unavailable or nonexistent.\r\n");
484 send(client, buf, strlen(buf), 0);
485 sprintf(buf, "</BODY></HTML>\r\n");
486 send(client, buf, strlen(buf), 0);
487 }
488
489 void serve_file(int client, const char *filename)
490 {
491 /**
492 * 局部變量說明:
493 * 1.resource : 打開的文件的文件指針;
494 * 2.numchars : 每次讀到的字符個(gè)數(shù);
495 * 3.buf : buffer的縮寫.
496 */
497 FILE *resource = NULL;
498 int numchars = 1;
499 char buf[1024];
500
501 /**
502 * 在本程序中消息頭對(duì)于純GET請(qǐng)求沒有什么用,直接讀取丟掉.
503 */
504 buf[0] = 'A'; buf[1] = '\0';
505 while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
506 numchars = get_line(client, buf, sizeof(buf));
507
508 resource = fopen(filename, "r");
509 if (resource == NULL)
510 not_found(client);
511 else
512 {
513 /* 發(fā)送消息頭 */
514 headers(client, filename);
515 /* 發(fā)送內(nèi)容實(shí)體 */
516 cat(client, resource);
517 }
518 fclose(resource);
519 }
520
521 /**
522 * startup 函數(shù)完成內(nèi)容:
523 * 1.獲取一個(gè)作為服務(wù)器的socket;
524 * 2.綁定服務(wù)器端的socket;
525 * 3.通過判斷參數(shù)port的值,確定是否需要?jiǎng)討B(tài)分配端口號(hào);
526 * 4.服務(wù)器開啟監(jiān)聽;
527 * 5.返回服務(wù)器段的socket文件描述符.
528 */
529 int startup(u_short *port)
530 {
531 /**
532 * 局部變量說明:
533 * 1.httpd : 保存服務(wù)器socket描述符,并作為返回值返回;
534 * 2.name : 用于保存服務(wù)器本身的socket信息,創(chuàng)建服務(wù)器.
535 */
536 int httpd = 0;
537 struct sockaddr_in name;
538
539 httpd = socket(PF_INET, SOCK_STREAM, 0);
540 if (httpd == -1)
541 error_die("socket");
542
543 memset(&name, 0, sizeof(name));
544 name.sin_family = AF_INET;
545 name.sin_port = htons(*port);
546 name.sin_addr.s_addr = htonl(INADDR_ANY);
547
548 if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
549 error_die("bind");
550
551 if (*port == 0) /* if dynamically allocating a port */
552 {
553 int namelen = sizeof(name);
554 if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
555 error_die("getsockname");
556 *port = ntohs(name.sin_port);
557 }
558
559 if (listen(httpd, 5) < 0)
560 error_die("listen");
561 return(httpd);
562 }
563
564 void unimplemented(int client)
565 {
566 char buf[1024];
567
568 sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
569 send(client, buf, strlen(buf), 0);
570 sprintf(buf, SERVER_STRING);
571 send(client, buf, strlen(buf), 0);
572 sprintf(buf, "Content-Type: text/html\r\n");
573 send(client, buf, strlen(buf), 0);
574 sprintf(buf, "\r\n");
575 send(client, buf, strlen(buf), 0);
576 sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
577 send(client, buf, strlen(buf), 0);
578 sprintf(buf, "</TITLE></HEAD>\r\n");
579 send(client, buf, strlen(buf), 0);
580 sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
581 send(client, buf, strlen(buf), 0);
582 sprintf(buf, "</BODY></HTML>\r\n");
583 send(client, buf, strlen(buf), 0);
584 }
585
586 /**********************************************************************/
587
588 int main(void)
589 {
590 /**
591 * 局部變量說明:
592 * 1.server_sock : 服務(wù)器端的socket描述符;
593 * 2.port : 服務(wù)器端的socket端口號(hào),如果是0的,startup()將會(huì)采用
594 * 自動(dòng)生成的方式生成新的端口號(hào)供使用;
595 * 3.client_sock : 客戶端連接進(jìn)來產(chǎn)生的客戶端socket描述符;
596 * 4.client_name : 用于保存客戶端連接進(jìn)來的socket信息;
597 * 5.client_name_len : struct sockaddr_in結(jié)構(gòu)體的大小,在accpet的時(shí)候
598 * 需要用到,這個(gè)參數(shù)必須傳,否則會(huì)出錯(cuò);
599 * 6.newthread : 用于保存新創(chuàng)建的線程的ID.
600 */
601 int server_sock = -1;
602 u_short port = 0;
603 int client_sock = -1;
604 struct sockaddr_in client_name;
605 int client_name_len = sizeof(client_name);
606 pthread_t newthread;
607
608 /**
609 * startup 函數(shù)完成內(nèi)容:
610 * 1.獲取一個(gè)作為服務(wù)器的socket;
611 * 2.幫定服務(wù)器斷的sockt;
612 * 3.通過判斷參數(shù)port的值,確定是否需要?jiǎng)討B(tài)分配端口號(hào);
613 * 4.服務(wù)器開啟監(jiān)聽.
614 */
615 server_sock = startup(&port);
616 printf("httpd running on port %d\n", port);
617
618 while (1)
619 {
620 /**
621 * 等待客戶端的連接,使用client_name保存客戶端socket信息,
622 * client_name_len是client_name對(duì)應(yīng)結(jié)構(gòu)體的長度.
623 */
624 client_sock = accept(server_sock,
625 (struct sockaddr *)&client_name,
626 &client_name_len);
627 if (client_sock == -1)
628 error_die("accept");
629 /**
630 * 創(chuàng)建一個(gè)新的線程來處理任務(wù),并把客戶端的socket描述符作為參數(shù)傳給accept_request,
631 * accept_request 函數(shù)說明:
632 * 1.獲取請(qǐng)求方式,目前只支持GET、POST請(qǐng)求;
633 * 2.在本程序中所有的POST請(qǐng)求、帶參數(shù)的GET請(qǐng)求都都被定義為訪問cgi程序;
634 * 3.從帶參數(shù)的GET請(qǐng)求中分離出請(qǐng)求參數(shù);
635 * 4.如果沒有指定需要訪問的文件,使用index.html文件作為默認(rèn)訪問文件;
636 * 5.檢查需要訪問的文件是否存在,以及其是否具有對(duì)應(yīng)的權(quán)限;
637 * 6.根據(jù)是否是cgi程序訪問,來執(zhí)行對(duì)應(yīng)的任務(wù).
638 */
639 if (pthread_create(&newthread , NULL, accept_request, client_sock) != 0)
640 perror("pthread_create");
641 }
642
643 /**
644 * 不知道為什么,這條語句在while外邊,竟然會(huì)影響到程序的關(guān)閉 :(
645 * 這行代碼注釋掉才能連續(xù)訪問,不注釋,只能訪問一次,所以直接注釋了
646 * 反正程序停止都使用ctrl+c,不影響程序的運(yùn)行.
647 */
648 //close(server_sock);
649
650 return(0);
651 }
?
轉(zhuǎn)載于:https://www.cnblogs.com/zengjfgit/p/4308459.html
總結(jié)
以上是生活随笔為你收集整理的tinyhttpd-0.1.0_hacking的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql的limit使用方法
- 下一篇: j2ee包含的标准