码迷,mamicode.com
首页 > Web开发 > 详细

【OpenSource】--TinyHttpD

时间:2016-01-22 17:39:30      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

【源码下载】http://sourceforge.net/projects/tinyhttpd/files/tinyhttpd%20source/tinyhttpd%200.1.0/tinyhttpd-0.1.0.tar.gz/download

【编译环境】ubuntu14.04+gcc

【运  行】工程利用了多线程,需要链接多线程的库libpthread.so;直接编译httpd.c源文件 $ gcc -o 程序名 源文件.c -lpthread   然后在浏览器输入: localhost:程序动态分配的端口号/index.html就可运行了。

请求头:

1 【GET】【http://localhost:59776/index.html】
2 Host: localhost:59776
3 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:39.0) Gecko/20100101 Firefox/39.0
4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
5 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
6 Accept-Encoding: gzip, deflate
7 Connection: keep-alive

响应头:

1 Content-Type: text/html
2 Server: jdbhttpd/0.1.0

 

【注  意】源代码中提示将多线程注释掉,注释掉后直接编译不能运行。不注释直接编译虽然会又warnning但可运行。

服务器端原理:

服务器端调用socket()建立socket套接字,调用bind()函数绑定IP和端口,调用listen()函数监听端口,等待浏览器发送URL,调用accept()函数接受数据,关闭套接字。

accept()函数中创建多线程,主线程继续等待,子线程处理http请求,解析浏览器发送的URL字符串,结束后新线程退出。

main():

 1 int main(void)
 2 {
 3      int server_sock = -1;
 4      u_short port = 0;
 5      int client_sock = -1;
 6      struct sockaddr_in client_name;
 7      int client_name_len = sizeof(client_name);
 8      pthread_t newthread;
 9 
10      server_sock = startup(&port);    //传递port的地址到startup()函数
11      printf("httpd running on port %d\n", port);
12 
13      while (1)
14      {
15           client_sock = accept(server_sock,
16                                (struct sockaddr *)&client_name,
17                                &client_name_len);
18           if (client_sock == -1)
19            error_die("accept");
20          /* accept_request(client_sock); */
21          if (pthread_create(&newthread , NULL, accept_request, client_sock) != 0)
22            perror("pthread_create");
23      }
24 
25      close(server_sock);
26 
27      return(0);
28 }

主函数调用startup()函数创建套接字。其中有一点是sockaddr和sockaddr_in的不同,总结是先创建sockaddr_in结构体,将该结构体中的各个变量赋值完后,在bind()或者accept()函数中将其转化为sockaddr结构体,因为两者所占内存空间一样可相互转化,另外两者所在头文件不一样,sockaddr在socket.h中,sockaddr_in在in.h中。

startup():

 1 int startup(u_short *port)
 2 {
 3      int httpd = 0;
 4      struct sockaddr_in name;    //声明结构体
 5 
 6      httpd = socket(PF_INET, SOCK_STREAM, 0);    //创建套接字
 7      if (httpd == -1)
 8       error_die("socket");
 9      memset(&name, 0, sizeof(name));    //初始化
10      name.sin_family = AF_INET;            //协议簇赋值
11      name.sin_port = htons(*port);
12      name.sin_addr.s_addr = htonl(INADDR_ANY);
13      if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)    //绑定IP和端口
14       error_die("bind");
15      if (*port == 0)  /* if dynamically allocating a port */
16      {
17           int namelen = sizeof(name);
18           if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
19            error_die("getsockname");
20           *port = ntohs(name.sin_port);//动态分配端口
21      }
22      if (listen(httpd, 5) < 0)    //监听套接字
23       error_die("listen");
24      return(httpd);    //返回套接字
25 }

startup()函数返回套接字后创建多线程,多线程函数起始为accept_request()函数。

accept_request():

 1 void accept_request(int client)
 2 {
 3      char buf[1024];
 4      int numchars;
 5      char method[255];
 6      char url[255];
 7      char path[512];
 8      size_t i, j;
 9      struct stat st;
10      int cgi = 0;      /* becomes true if server decides this is a CGI
11                         * program */
12      char *query_string = NULL;
13 
14      numchars = get_line(client, buf, sizeof(buf));
15      i = 0; j = 0;
16      while (!ISspace(buf[j]) && (i < sizeof(method) - 1))
17      {
18           method[i] = buf[j];
19           i++; j++;
20      }
21      method[i] = \0;
22         //判断请求方式
23      if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
24      {
25           unimplemented(client);
26           return;
27      }
28 
29      if (strcasecmp(method, "POST") == 0)
30       cgi = 1;
31 
32      i = 0;
33      while (ISspace(buf[j]) && (j < sizeof(buf)))
34       j++;
35      while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf)))
36      {
37           url[i] = buf[j];
38           i++; j++;
39      }
40      url[i] = \0;
41     //GET方式
42      if (strcasecmp(method, "GET") == 0)
43      {
44           query_string = url;
45           while ((*query_string != ?) && (*query_string != \0))
46            query_string++;
47           if (*query_string == ?)
48           {
49                cgi = 1;
50                *query_string = \0;
51                query_string++;
52           }
53      }
54      sprintf(path, "htdocs%s", url);//默认路径为工程下的htddocs文件夹下index.html
55      if (path[strlen(path) - 1] == /)
56       strcat(path, "index.html");
57      if (stat(path, &st) == -1) {
58       while ((numchars > 0) && strcmp("\n", buf))  /* read & discard headers */
59            numchars = get_line(client, buf, sizeof(buf));
60           not_found(client);
61      }
62      else
63      {
64       if ((st.st_mode & S_IFMT) == S_IFDIR)
65        strcat(path, "/index.html");
66       if ((st.st_mode & S_IXUSR) ||
67           (st.st_mode & S_IXGRP) ||
68           (st.st_mode & S_IXOTH)    )
69        cgi = 1;
70       if (!cgi)
71        serve_file(client, path);    //处理静态页面
72       else
73        execute_cgi(client, path, method, query_string);
74      }
75 
76      close(client);
77 }

 处理静态文件函数serv_file():

发送一个文件到客户端,调用headers()发送响应头。调用cat()函数将一个文件的内容输出到socket。

 1 void serve_file(int client, const char *filename)
 2 {
 3      FILE *resource = NULL;
 4      int numchars = 1;
 5      char buf[1024];
 6 
 7      buf[0] = A; buf[1] = \0;
 8      while ((numchars > 0) && strcmp("\n", buf))  /* read & discard headers */
 9      //读取一行,将以\n或\r\n结束的字符串,转化为以\n\0字符结束
10       numchars = get_line(client, buf, sizeof(buf));
11 
12      resource = fopen(filename, "r");
13      if (resource == NULL)
14           not_found(client);
15      else
16      {
17              //响应头
18           headers(client, filename);
19           cat(client, resource);
20      }
21      fclose(resource);
22 }
23 void headers(int client, const char *filename)
24 {
25      char buf[1024];
26      (void)filename;  /* could use filename to determine file type */
27 
28      strcpy(buf, "HTTP/1.0 200 OK\r\n");
29      send(client, buf, strlen(buf), 0);
30      strcpy(buf, SERVER_STRING);
31      send(client, buf, strlen(buf), 0);
32      sprintf(buf, "Content-Type: text/html\r\n");
33      send(client, buf, strlen(buf), 0);
34      strcpy(buf, "\r\n");
35      send(client, buf, strlen(buf), 0);
36 }
37 void cat(int client, FILE *resource)
38 {
39      char buf[1024];
40 
41      fgets(buf, sizeof(buf), resource);
42      while (!feof(resource))
43      {
44           send(client, buf, strlen(buf), 0);
45           fgets(buf, sizeof(buf), resource);
46      }
47 }

 

【OpenSource】--TinyHttpD

标签:

原文地址:http://www.cnblogs.com/gjbmxy/p/5151568.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!