IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    tinyhttpd源码剖析

    armsword发表于 2014-11-22 16:25:14
    love 0

    喊了几天学习Web开发,为了毕业论文,今晚上计划也是看看CSS呢,但是实在是没忍住,读了下经典的tinyhttp的源代码,这款代码还是颇有名气的,网上这么评论的:

    tinyhttpd是一个超轻量型Http Server,使用C语言开发,全部代码只有500、600行,附带一个简单的Client,可以通过阅读这段代码理解一个Http Server的本质。

    其实,代码颇简单,适合刚学习Web Server的童鞋学习,因为我之前写过CGI Server,所以,我还是认为此代码写的一般,并且我在Ubuntu下编译遇到了不少错误,我都懒得写详细分析了,所以随便写下吧,后面的Github地址里有详细的分析。

    源码下载地址:http://sourceforge.net/projects/tinyhttpd/

    make编译后会有不少错误和警告,我这里说下怎么改正错误:

    1、Makefile文件里的:gcc -W -Wall -lsocket -lpthread -o httpd httpd.c ,修改为:

    gcc -W -Wall -o httpd httpd.c -lpthread

    2、481行的 int client_name_len 改为 socklen_t client_name_len

    3、436行 改动与上面相似,改为socklen_t类型即可。

    4、34行改为void accept_request(void ); 所以下面的实现也要修改下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void *accept_request(void* client1)
    {
    int client = *(int *)client1;
    char buf[1024];
    // 省略
    同时注意此函数77 和129行改为return NULL;
    497行改为if (pthread_create(&newthread; , NULL, accept_request, (void*)client_sock) != 0)

    之后再make,程序就OK了。

    简单说下程序的逻辑吧:

    一个无限循环,一个请求,创建一个线程,之后线程处理函数处理每个请求,然后解析HTTP请求,然后做一些判断处理,之后判断文件是否可执行,不可执行,打开文件,输出给客户端(浏览器)呗,可执行就创建管道,父子进程通信。

    整个流程就这么简单,程序主要处理2种HTTP请求方式:GET和POST,懒得说了,上传两张图片,自己分析吧,图片原始出处不清楚,电脑里存了好久了,。

    GET:

    POST:

    其实这个源码里有一个地方比较难懂,就是那个解析HTTP每一行的那个get_line函数里的recv的MSG_PEEK参数,详细解释可以参考此链接。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    // 读取socket,判断换行,CRLF标志,之后以"\n"换行,并在字符串后添加'\0'
    int get_line(int sock, char *buf, int size)
    {
    int i = 0;
    char c = '\0';
    int n;
    while ((i < size - 1) && (c != '\n'))
    {
    // 一个字符一个字符的读取
    n = recv(sock, &c;, 1, 0);
    /* DEBUG printf("%02X\n", c); */
    if (n > 0)
    {
    if (c == '\r')
    {
    /*
    * 注意MSG_PEEK参数,表示TCP Buffer不删除之前队列数据,从队列里接收数据
    */
    n = recv(sock, &c;, 1, MSG_PEEK);
    /* DEBUG printf("%02X\n", c); */
    if ((n > 0) && (c == '\n'))
    recv(sock, &c;, 1, 0);
    else
    c = '\n';
    }
    buf[i] = c;
    i++;
    }
    else
    c = '\n';
    }
    buf[i] = '\0';
    return(i);
    }

    这代码,没啥写头,很多功能都没实现,请求只实现了GET和POST,Header里只用了第一行,CGI里全局变量只定义了几个,并且我验证程序,发现CGI功能好像是有些问题的,但是因为我CGI水平比较水,懒得检测原因了,总体来说,程序比我之前的那个CGI Server要简单些,功能要稍微弱些吧。

    下面放出我Github里的详细中文注释,欢迎指正,谢谢:

    https://github.com/armsword/Source/tree/master/tinyhttpd



沪ICP备19023445号-2号
友情链接