• LightHttpd源码分析


    源码: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(以 、 或 结尾的串):调用 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()。
     
  • 相关阅读:
    BZOJ.1028.[JSOI2007]麻将(贪心)
    BZOJ.1024.[SCOI2009]生日快乐(记忆化搜索)
    BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)
    BZOJ.1026.[SCOI2009]windy数(数位DP)
    BZOJ.2125.最短路(仙人掌 最短路Dijkstra)
    BZOJ.1021.[SHOI2008]循环的债务(DP)
    BZOJ.1019.[SHOI2008]汉诺塔(递推)
    POJ.1379.Run Away(模拟退火)
    BZOJ.3680.吊打XXX(模拟退火/爬山算法)
    BZOJ.1018.[SHOI2008]堵塞的交通(线段树维护连通性)
  • 原文地址:https://www.cnblogs.com/xxfcz/p/6165964.html
Copyright © 2020-2023  润新知