源码:https://github.com/EZLippi/Tinyhttpd

要在Linux中编译,无需像代码注释所说那样:

/* This program compiles for Sparc Solaris 2.6.
* To compile for Linux:
* 1) Comment out the #include <pthread.h> line.
* 2) Comment out the line that defines the variable newthread.
* 3) Comment out the two lines that run pthread_create().
* 4) Uncomment the line that runs accept_request().
* 5) Remove -lsocket from the Makefile.
*/

直接编译即可。

编译,有警告:

httpd.c:282: warning: not enough variable arguments to fit a sentinel

对应代码:

execl(path, NULL);

解决办法:添加一个参数NULL,即修改为:

execl(path, NULL, NULL);

主要函数一览:

bad_request: 返回给客户端这是个错误请求,HTTP 状态吗 400 BAD REQUEST.
cat: 读取服务器上某个文件写到 socket 套接字。
cannot_execute: 主要处理发生在执行 cgi 程序时出现的错误。
error_die: 把错误信息写到 perror 并退出。
execute_cgi: 运行 cgi 程序的处理,也是个主要函数。
get_line: 读取套接字的一行,把回车换行等情况都统一为换行符结束。
headers: 把 HTTP 响应的头部写到套接字。
not_found: 主要处理找不到请求的文件时的情况。
sever_file: 调用 cat 把服务器文件返回给浏览器。
startup: 初始化 httpd 服务,包括建立套接字,绑定端口,进行监听等。
unimplemented: 返回给浏览器表明收到的 HTTP 请求所用的 method 不被支持
 
 
 
函数main():
  1. 调用 startup()创建TCP服务器监听套接字 server_sock。
  2. 无限循环 反复执行
    1. 接受客户端连接:调用 accept()
    2. 创建处理线程:调用 pthread_create()
  3. 关闭 server_sock。
  4. 结束。■
 
  
函数accept_request(client):处理一个HTTP请求。
  1. 从连接套接字client读入下一行至buf(以\r\n、\r或\n结尾的串):调用 get_line()。
  2. 从buf取请求方法至method
  3. 若方法不是"GET"也不是"POST",则发送“方法未实现”的响应;结束。■
  4. 若方法是"GET",则寻找'?';若有,则取其后的查询参数到query_string,并置CGI标志cgi为1。
  5. 从buf取请求路径至url
  6. 把url串接到 "htdocs"后面,得到path,例如:htdocs/dir/file1.html
  7. 若path以'/'结尾,则自动接上默认文档名 "index.html"
  8. 判断path的文件类型:调用stat()
  9. 若文件不存在,则
    1. 从client读入并丢弃头部
    2. 发送响应:文件未找到
    3. 结束。■
  10. 若path是目录,则 path后面接上 "/index.html"
  11. 若path可执行,则置cgi为1
  12. 如果是cgi,则执行之:调用 execute_cgi()
  13. 否则发送文件:调用 serve_file()
  14. 关闭client,结束。■
 
小结:
此函数中首先解析客户端的请求方式,是GET,还是POST。tinyhttpd只能处理这2种请求,如果都不是,就返回错误。然后解析请求的url,对应到服务器中tinyhttpd中htdocs目录下的文件,检查文件状态,如果文件不存在,那么返回错误。如果文件存在,是GET方法时,tinyhttpd直接返回此文件,通常是html。如果是POST,那么会执行对应的.cgi文件。
 
  
函数:serve_file(int client, const char *filename)
功能:向客户端client发送文件filename
步骤:
  1. 从client读入头部并丢弃。
  2. 以只读方式打开文件filename
  3. 若出错,则发送响应:文件未找到;结束。■
  4. 发送文件:调用cat()
  5. 结束。■
 
 
函数:execute_cgi() 略。
    等用到CGI时再说。
 
学到的技巧:
  • 预读socket而不取走数据:recv(sock, &c, 1, MSG_PEEK);
  • fgets/fputs()只能用于读写文本文件。要读写二进制文件,请使用fread/fwrite()。
 

LightHttpd源码分析的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

随机推荐

  1. 一看就懂得移动端rem布局、rem如何换算

    这里使用了js控制根元素的font-size大小,然后进行rem换算,在js代码后面会说明以下问题. 1.如何进行rem运算? 2.如果纯js控制根元素用rem布局会出现的小问题,如何解决? 3.如有 ...

  2. Jquery遍历选中的input标签

    $("input[name='chkAgent']:[checked]").each(function () { alert($(this).attr("value&qu ...

  3. 启用与关闭 Ad Hoc Distributed Queries

    在数据库里执行以下脚本: 启用: exec sp_configure 'show advanced options',1reconfigureexec sp_configure 'Ad Hoc Dis ...

  4. sql server数据库操作

    --插入整行数据 , '1983-08-29', 'A', 'A', 'A') --插入部分列数据 , '1983-08-29') --删除行记录 delete from person where n ...

  5. Noip2016提高组 组合数问题problem

    Day2 T1 题目大意 告诉你组合数公式,其中n!=1*2*3*4*5*...*n:意思是从n个物体取出m个物体的方案数 现给定n.m.k,问在所有i(1<=i<=n),所有j(1< ...

  6. CodeSmith Merge策略--小白教程

        为了让 自动产生的代码 和 程序员手写的代码 互不干涉, 提出了Merge策略, 包括以下三种 InsertRegion: 只插入(覆盖)到指定 #region区域 InsertClass: ...

  7. android创建桌面快捷方式(启动目标非项目的启动页)

    1.布局文件中,目标Activity加入以下filter <intent-filter>                  <action android:name="an ...

  8. 問題排查:DataGridView 資料行下拉選單,資料繫結階段顯示 DataGridViewComboBoxCell 值無效

    可能原因: 1.下拉選單的選項資料繫結晚於 DataGridView 的資料繫結 2.下拉選單的 DataPropertyName 屬性,比 DisplayMember.ValueMember 早賦值 ...

  9. IntelliJ IDEA 2016.2激活方法

    IntelliJ IDEA 2016.2激活 激活码 43B4A73YYJ-> eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoib ...

  10. DDX_Text ()函数 C++

    DDX_Text()函数管理着对话框.表格视或控件视对象中的编辑控件与对话框.表格视或控件视对象的CString型数据成员之间的int,UINT,long,DWORD,CString,float或do ...