【OpenSource】--TinyHttpD

【源码下载】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 }
时间: 2024-10-18 19:46:52

【OpenSource】--TinyHttpD的相关文章

【ABAP】SELECT-ENDSELECT尽量不要用

ABAP中支持一种SELECT-ENDSELECT的结构,就是可以在SELECT中对取得的每一行数据(或是几个字段)可以先放入一个行结构(或是几个字段)中,再做处理.初看似乎觉得蛮有用的,的确这个结构本身就是为了方便处理数据的.但是,如果你滥用了这种结构,那么会严重影响程序性能.我接触过的一个报表程序就是用了这种结构,结果系统运行半年后,这张报表就不能用,原因是什么呢?就是因为数据量大了之后,在SELECT和END SELECT之间做处理的时间会很长,从而导致数据库端因为连接超时而断开.由此可以

【OpenSource】--Web Bench 1.5

[简介]linux下开源软件webbench-1.5简介 Web Bench is very simple tool for benchmarking WWW or proxy servers. Uses fork() for simulating multiple clients and can use HTTP/0.9-HTTP/1.1 requests. This benchmark is not very realistic, but it can test if your HTTPD

【干货】ORACLE-AWR报告分析

1.什么是AWR? AWR (Automatic Workload Repository) 是自动负载信息库的英文缩写,AWR报告是Oracle 10g以后版本提供的一种性能收集和分析工具,能提供一个时间段内整个系统资源使用情况的报告,通过报告可以了解一个系统的整个运行情况,生成的报告包括多个部分. AWR每小时对v$active_session_history视图(内存中的ASH采集信息,理论为1小时)进行采样一次,并将信息保存到磁盘中,并且保留7天,7天后旧的记录才会被覆盖.这些采样信息被保

【转载】中国互联网--墙的故事

互联网 - 互联半个中国 截至2012年底,中国网民数量达5.64亿,全国共有网站268万.(数据来源:中国互联网络信息中心CNNIC). 内外有别 海底光缆.同步卫星将中国的网络与国际互联网紧密联结,中国的网络出口带宽达每秒数百万兆.然而,许多在境外能够流畅访问的网站,在中国境内却是无法访问的,比如Twitter, Facebook, YouTube等.德国之声也不幸位列其中. 官方从未正式承认的高墙 与那些不受官方待见的网站所进行的数据通讯,将会被一套精密的系统所拦截.阻断.民间通常把它称作

【python】python-os模块的常用函数

部分安卓手机的文件路径为/storage/emulated/0/文件或文件夹名 os.path.join('bin','usr'-) 返回一个字符串,bin/usros.getcwd() 返回字符串 当前目录os.chdir() 设置工作路径os.makedirs() 创建新的文件夹os.path.abspath() 传入相对路径,返回绝对路径os.path.isabs() 传入字符串,返回布尔值,是相对路径返回True,反之Falseos.path.dirname() 传入字符串,返回最后一个

【综述】(中科院)樊彬老师-“局部图像特征描述概述”

[综述](中科院)樊彬老师-“局部图像特征描述概述” 这次我们荣幸地邀请到中国科学院自动化研究所的樊彬老师为我们撰写图像特征描述符方面的最新综述.樊彬老师在图像特征描述方面已连续发表了包括TPAMI.PR.ICCV.CVPR在内的多篇高质量论文.他的个人主页为:http://www.sigvc.org/bfan/ 以后我们将持续邀请国内外众多老师做最新的视觉计算专业综述报告,如特征提取和描述.稀疏表达.人体跟踪.三维衣服布料动画.轻量级Web3D等,并陆续在学术论坛上发布.各位老师会尽量使综述通

【综述】(MIT博士)林达华老师-&quot;概率模型与计算机视觉”

[综述](MIT博士)林达华老师-"概率模型与计算机视觉” 距上一次邀请中国科学院的樊彬老师为我们撰写图像特征描述符方面的综述(http://www.sigvc.org/bbs/thread-165-1-1.html)之后,这次我们荣幸地邀请到美国麻省理工学院(MIT)博士林达华老师为我们撰写“概率模型与计算机视觉”的最新综述.这次我们特别增设了一个问答环节,林老师针对论坛师生提出的许多问题(如概率图模型与目前很热的深度神经网络的联系和区别)一一做了详细解答,并附在综述的后面. 林达华老师博士毕

【插件】史上最强编辑器通用ctags插件OpenCTags使用指南v1.2--开发者必备

Changes Log: v1.2.0 2011-12-4 支持Java编写的可以设置用户配置的编辑工具 增加当前文件类查找Tags功能 增加设置当前目录参数 完善多种主流轻量级编辑器的配置 v1.1.0 2011-11-26 完善提示窗口的显示样式 编辑器配置使用Json格式配置文件,方便定制到自己喜欢的编辑器,主流编辑器一网打尽 v1.0.4 2011-11-21 支持提示窗口拖动,按住鼠标右键,即可拖拖拖[上一版本为鼠标左键] 增加回车键功能,按下可以会自动打开对应的文件并定位到对应的位置

【Open Search产品评测】-- 淘点点:基于OpenSearch,轻松实现一整套O2O类搜索解决方案

 [Open Search产品评测]--  淘点点:基于OpenSearch,轻松实现一整套O2O类搜索解决方案   [使用背景] 我们淘点点团队应该可以算是内网首批使用opensearch来搭建应用的团队了,在此之前,一直使用集团内一个基于lucene的引擎平台.对于淘点点特定的排序需求,都需要该团队配合升级,运维上共同维护.年初,集团推出Isearch5,然后又看到opensearch,一个基于Isearch5之上的搜索开放平台.听下来最令我们开心的就是:排序支持formula, 这样以后我