tinyhttpd初学分析

刚开始学习服务端相关的知识,对服务器程序没有了解,学习tinyhttpd是一个超轻量型的http server,可以用来了解服务器程序的本质和流程。Tinyhttpd的代码只有500行左右,比较易于阅读。

代码下载:https://sourceforge.net/projects/tinyhttpd/

linux虚拟机上运行程序可以参照:

https://blog.csdn.net/zhuang20170703/article/details/79867581

图解(参考https://www.cnblogs.com/nengm1988/p/7816618.html根据理解进行修改):


流程概述(参考https://blog.csdn.net/jcjc918/article/details/42129311):

1. 启动服务器,在指定端口或随机端口绑定httpd服务

2. 接收到一个http请求(就是listen监听的端口accept的时候),派生一个县城运行accept_request函数(在startup函数和main函数中体现)

3. 取出http请求中的method(GET或POST)和url。对于GET方法,如果携带查询参数,则query_string指针指向url中?后面的GET参数。

4. 格式化url到path数组,表示浏览器请求的服务器文件路径,在tinyhttpd中服务器文件是在htdocs文件夹下的。当url以/结尾,或url是个目录,则默认在path中加上index.html,表示访问的主页地址。

5. 如果文件合法,对于无参数的GET请求,直接输出服务器文件到浏览器(在serve_file函数中实现),即用http格式写到套接字上,跳到(10)。其他情况(带参数GET,POST方式,url问可执行文件),则调用execute_cgi函数执行cgi脚本文件。(3.4.5为accept_request函数的主要内容)。

6. 读取整个http请求并丢弃,如果是POST则找出content-length,把http200状态码写到套接字。

7. 建立两个管道,cgi_input和cgi_output,并fork一个进程

8. 在子进程中,把 STDOUT 重定向到 cgi_outputt 的写入端,把 STDIN 重定向到 cgi_input 的读取端,关闭 cgi_input 的写入端 和 cgi_output 的读取端,设置 request_method 的环境变量,GET 的话设置 query_string 的环境变量,POST 的话设置 content_length 的环境变量,这些环境变量都是为了给 cgi 脚本调用,接着用 execl 运行 cgi 程序。

9.  在父进程中,关闭 cgi_input 的读取端 和 cgi_output 的写入端,如果 POST 的话,把 POST 数据写入 cgi_input,已被重定向到 STDIN,读取 cgi_output 的管道输出到客户端,该管道输入是 STDOUT。接着关闭所有管道,等待子进程结束。(6.7.8.9均在execute_cgi函数实现)

10. 关闭与浏览器的连接,完成了一次 HTTP 请求与回应,因为 HTTP 是无连接的。

主要函数:

//函数说明:检查参数c是否为空格字符,
//也就是判断是否为空格(' ')、定位字符(' \t ')、CR(' \r ')、换行(' \n ')、垂直定位字符(' \v ')或翻页(' \f ')的情况。
//返回值:若参数c 为空白字符,则返回非 0,否则返回 0。
#define ISspace(x) isspace((int)(x))
#define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n"

//每次收到请求,创建一个线程来处理接受到的请求
//把client_sock转成地址作为参数传入pthread_create
void *accept_request(void *);
//错误请求,返回400响应码
void bad_request(int);
//读取文件,写到socket套接字
void cat(int, FILE *);
//无法执行cgi程序
void cannot_execute(int);
//错误输出,写到perror
void error_die(const char *);
//执行cgi脚本,涉及脚本的动态解析
void execute_cgi(int, const char *, const char *, const char *);
//读取一行http报文,只要发现c是\n,则一行结束,如果读到\r,再用MSG_PEEK的方式读入一个字符,如果是\n,从socket读出
//如果是下一个字符则不处理,将c置为\n结束。如果读到的数据为0中断,或者小于1也视为结束,c置为\n
int get_line(int, char *, int);
//返回http头
void headers(int, const char *);
//没有发现文件
void not_found(int);
//如果不是CGI文件则调用cat()直接读取文件返回给请求的http客户端
void serve_file(int, const char *);
//开启tcp连接,绑定端口等操作;开启http服务,包括端口,监听,开启线程处理链接
int startup(u_short *);
//如果不是Get或者Post,就报方法没有实现;返回给浏览器,表明收到的http请求所用的method不被支持
void unimplemented(int);

代码详解:

/* J. David's webserver */
/* This is a simple webserver.
 * Created November 1999 by J. David Blackstone.
 * CSE 4344 (Network concepts), Prof. Zeigler
 * University of Texas at Arlington
 */
/* 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.
 */
#include <stdio.
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值