1. 简介:
tinyhttpd是使用c语言开发的超轻量级http服务器,通过代码流程可以了解http服务器的基本处理流程,
并且涉及了网络套接字,线程,父子进程,管道等等知识点;
项目地址:http://sourceforge.net/projects/tinyhttpd/
2. 流程介绍:
(1) 服务器启动,等待客户端请求到来;
(2) 客户端请求到来,创建新线程处理该请求;
(3) 读取httpHeader中的method,截取url,其中GET方法需要记录url问号之后的参数串;
(4) 根据url构造完整路径,如果是/结尾,则指定为该目录下的index.html;
(5) 获取文件信息,如果找不到文件,返回404,找到文件则判断文件权限;
(6) 如果是GET请求并且没有参数,或者文件不可执行,则直接将文件内容构造http信息返回给客户端;
(7) 如果是GET带参数,POST,文件可执行,则执行CGI;
(8) GET请求略过httpHeader,POST方法需要记录httpHeader中的Content-Length:xx;
(9) 创建管道用于父子进程通信,fork产生子进程;
(10) 子进程设置环境变量,将标准输入和输出与管道相连,并且通过exec执行CGI;
(11) 如果是POST,父进程将读到post内容发送给子进程,并且接收子进程的输出,输出给客户端;
3. 管道说明:
4. 代码注释:
1 /* J. David's webserver */ 2 /* This is a simple webserver. 3 * Created November 1999 by J. David Blackstone. 4 * CSE 4344 (Network concepts), Prof. Zeigler 5 * University of Texas at Arlington 6 */ 7 /* This program compiles for Sparc Solaris 2.6. 8 * To compile for Linux: 9 * 1) Comment out the #include <pthread.h> line. 10 * 2) Comment out the line that defines the variable newthread. 11 * 3) Comment out the two lines that run pthread_create(). 12 * 4) Uncomment the line that runs accept_request(). 13 * 5) Remove -lsocket from the Makefile. 14 */ 15 #include <stdio.h> 16 #include <sys/socket.h> 17 #include <sys/types.h> 18 #include <netinet/in.h> 19 #include <arpa/inet.h> 20 #include <unistd.h> 21 #include <ctype.h> 22 #include <strings.h> 23 #include <string.h> 24 #include <sys/stat.h> 25 #include <pthread.h> 26 #include <sys/wait.h> 27 #include <stdlib.h> 28 29 #define ISspace(x) isspace((int)(x)) 30 31 #define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n" 32 33 void accept_request(int); 34 void bad_request(int); 35 void cat(int, FILE *); 36 void cannot_execute(int); 37 void error_die(const char *); 38 void execute_cgi(int, const char *, const char *, const char *); 39 int get_line(int, char *, int); 40 void headers(int, const char *); 41 void not_found(int); 42 void serve_file(int, const char *); 43 int startup(u_short *); 44 void unimplemented(int); 45 46 /**********************************************************************/ 47 /* A request has caused a call to accept() on the server port to 48 * return. Process the request appropriately. 49 * Parameters: the socket connected to the client */ 50 /**********************************************************************/ 51 void accept_request(int client) 52 { 53 char buf[1024]; 54 int numchars; 55 char method[255]; 56 char url[255]; 57 char path[512]; 58 size_t i, j; 59 struct stat st; 60 int cgi = 0; /* becomes true if server decides this is a CGI 61 * program */ 62 char *query_string = NULL; 63 64 //读取第一行数据 65 numchars = get_line(client, buf, sizeof(buf)); 66 i = 0; j = 0; 67 //读取http的头部method字段,读到空白为止 68 while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) 69 { 70 method[i] = buf[j]; 71 i++; j++; 72 } 73 method[i] = '\0'; 74 75 //只支持GET和POST请求,其他请求方式返回未实现 76 if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) 77 { 78 unimplemented(client); 79 return; 80 } 81 //如果是POST请求,设置cgi标志为1 82 if (strcasecmp(method, "POST") == 0) 83 cgi = 1; 84 85 i = 0; 86 //跳过空白字符 87 while (ISspace(buf[j]) && (j < sizeof(buf))) 88 j++; 89 //读取url字串 90 while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) 91 { 92 url[i] = buf[j]; 93 i++; j++; 94 } 95 url[i] = '\0'; 96 //如果是GET请求,需要从url中解析参数 97 if (strcasecmp(method, "GET") == 0) 98 { 99 query_string = url; 100 //找到?位置 101 while ((*query_string != '?') && (*query_string != '\0')) 102 query_string++; 103 //当前字符为?字符 104 if (*query_string == '