开源代码学习之Tinyhttpd

   
想起来陆续探究一些感兴趣的开源代码于是先挑一个代码量短的来连接一下,写这篇博客的目标是记录下团结上学的过程。Tinyhttpd算是一个袖珍的web服务器,浏览器与Web服务器之间的通信接纳的是Http,所以一开头的切入点是HTTP协议,这里说一些即便有做HTTP通信的付出依然看一下RFC中对不同版本HTTP的概念,以下原理部分都是从《后台开发:主旨技术与应用实践》中HTTP协议章节中裁剪出来的,对后台感兴趣的同窗可以看一下,讲述后台开发所急需所有的技艺点一本很正确的书。

一、HTTP协议

HTTP工作流程:

  在OSI七层模型中,HTTP是依照TCP上的应用层协议而大家所说的HTTPS基于同处于应用层的TLS、SSL协议层之上。HTTP默认的端口号为80,HTTPS默认的端口号为443。在HTTP1.1中(通过Connection头设置)默认在HTTP传输完成后持续开TCP连接,往日的HTTP版本则默认是断开连接的,也就是说本次请求与上次请求是不同的多少个TCP连接。一遍HTTP操作称为一个事情,其行事历程可以分成以下四步。

  (1)首先客户机与服务器需要建立连接 。 只要单击某个超级链接, HTTP
的干活即起来 。
  (2)建立连接后,客户机发送一个请求给服务器,请求形式的格式为:统一资源标识符(URL
)、协议版本号,后面是 MIME
信息(包括请求修饰符、客户机音讯和可能的情节) 。

  (3)服务器收到请求后,给予相应的响应信息,其格式为一个意况行,包括音信的磋商版本号、一个成功或错误的代码,后面是
MTh伍信息(包括服务器音信、实体音讯和可能的情节) 。

  (4)客户端接收服务器所再次回到的信息透过浏览器呈现在用户的显示屏上,然后客户机与劳动器断开连接

HTTP协议结构:

  HTTP 协议无论是请求报文依然答应报文,都分为以下 4 个部分 。

  (1)报文头( initial line ),下面的例子中的“ GET
http://www.baidu.com/favicon.icoHTTP/1.1 ”表示用 GET 方法请求
http://www.baidu.com/favicon. ic。这多少个文件,用的是HTTP/1.1 协议。

  (2) 0 个或七个请求头( header line ),例如 Accept-Language: en

  (3)空行(作为 header lines 的结束) 。

  (4)可选的音信体 。

  HTTP 协议是基于行的商事,每一行 以 \r\n 作为分隔符 。
报文头日常表明报文的门类(例如请求类型),且报文头只占一行
;请求头附带一些相当音信,每一个请求头占一行,其格式为 name:value
,即以分行作为分隔; 空行也就以一个 \r\n 分隔;可选 body
通常包含数据,例如服务器重返的某个静态 HTML 文件的内容 。

  HTTP请求方法:

  HTTP/ 1.1 协议中共定义了 9 种办法(有时也叫“动作”)来表 明
Request-URI 指定的资源的例外操作方法,如下所述。

  ( 1 ) OPTIONS :重回服务器针对一定资源所支撑的 HTTP
请求方法;也足以运用向 Web服务器发送“*”的请求来测试服务器的功效性。

  ( 2) HEAD :向服务器需要与 GET
请求相平等的响应,只但是响应体将不会被再次来到 。
这一艺术可以在不必传输整个响应内容的情状下,就足以收获包含在响应音讯头中的元信息。该方法常用于测试超链接的灵光,是否足以访问,以及新近是不是更新等信息。

  ( 3) GET :向特定的资源发出请求 。 注意 : GET
方法不应有被用于爆发“副功用”的操作中,例如在 web app .
中的应用,其中一个缘故是 GET 可能会被网络蜘蛛等随意访问 。

  ( 4 ) POST
:向指定资源提交数据举办拍卖请求(例如提交表单或者上传文件) 。
数据被含有在请求体中 。 POST
请求可能会导致新的资源的创制或对已有资源的改动 。

  ( 5 ) PUT :向指定资源职务上传其最新内容 。

  ( 6) DELETE : 请求服务器删除 Request-URI 所标识的资源 。

  ( 7 ) TRACE :回显服务器收到的哀告,首要用来测试或确诊。

  ( 8) CONNECT: HTTP/ 1.1
协议中留下给可以将连续改为管道格局的代办服务器 。

  ( 9) PATCH :用来将有些修改应用于某一资源,该操作添加于规范盯C5789
中 。

  HTTP 服务器至少应当实现 GET 和 HEAD 方法,其他情势都是可选的 。
另外,除了上述方法,特定的 HTTP 服务器还是可以够壮大自定义的不二法门 。

  HTTP 常见的伸手头:

  在 HTTP/ l.l 协议中,所有的请求头(除 Host
外)都是可选的,因为Host重要用以请求的服务器的IP地址和端口号,请求头有Host、Connection、Accept、Accept-Encoding、User-Agent、Cookie等,请求头太多这里就不列出来了。

  HTTP回应报文:

  再次回到码由 3 位数字组成,第一个数字定义了响应的连串,且有 5
种可能的取值。

  ( 1 ) lxx :指示音信,表示请求已采纳,继续处理。

  ( 2) 2xx :成功,表示请求已被成功接收、了然 、 接受 。

  ( 3) 3xx :重定向,要成功请求必须开展更进一步的操作 。

  ( 4 ) 4xx :客户端错误,请求有语法错误或请求不能落实。

  ( 5) 5xx :服务器端错误,服务器未能实现合法的呼吁 。

  Date :表示音信发送的年月,时间的描述格式由 rfc822 定义 。

  Server : 指明 Web 服务器用来处理请求的软件信息 。

  Accept-Ranges : Web
服务器表明自己是否接受获取其某个实体的一局部(比如文件的一片段)的伸手
。 bytes 代表接到, none 表示不接收。

  Vary: Web 服务器用该头部的内容告诉 Cache
服务器,在什么样条件下才能用本响应所重返的靶子响应后续的乞求 。

  Content-Encoding : Web 服务器声明自己行使了什么压缩方法( gzip,
deflate)压缩响应中的对象。

  Content-Length: Web 服务器告诉浏览器自己响应的对象的长度 。

  Content-Type: Web 服务器告诉浏览器自己响应的对象的类型 。

二、CGI

  CGI ( Common Gateway Interface ,通用网关接口)是 HTTP
协议中最重大的技艺之一,有着不可取代的首要性地位 。 CGI 是一个 Web
服务器提供音信服务的标准接口 。 通过 CGI 接口, Web
服务器就可知取得客户端提交的音讯,转交给服务器端的 CGI
程序举行拍卖,最终回到结果给客户端 。 组成 CGI 通信系统的是两部分:
一部分是 HTML
页面,就是在用户端浏览器上呈现的页面;另一有的则是运作在服务器上的 CG I
程序 。

  浏览器只需要指定执行服务器上的哪位CGI程序就行,一般景色下,服务器和
CGI
程序之间是因而标准输入输出来展开多少传递的(就像tinyhttpd中调用CGI程序),而以此历程需要环境变茸的协作方可实现。环境变量在
CGI 中存有显要的身价,每个 CGI
程序只可以处理一个用户请求,所以在激活一个CGI程序进程时也开创了属于该过程的环境变量,CGI程序可以用Python、PERL、Shell、C或C++等语言来兑现。

  CGI 环境变量在 CGI 程序启动时起始化,在竣工时销毁。当一个 CGI
程序不是被 HTTP 服务器调用时,它的条件变盘几乎是系统环境变量的复制
。当以此 CGI 程序被 HTTP 服务器调用时,它的环境变量就会多了以下关于HTTP
服务器、客户端、 CGI 传输过程等门类。CGI 相关的环境变量有 3
种:与请求相关的环境变量、与服务器相关的环境变量和与客户端相关的环境变量,,详细见表
12-1 。

  图片 1

  CGI 工作规律:每当客户请求 CGI 的时候 Web
服务器就请求操作系统生成一个新的CGI
进程,该过程处理完请求后脱离,下一个伸手来时再成立新历程 。
当然,这样在访问量很少没有出现的情形使得,然而当访问量增大且并发存在时,这种艺术就不适合了,于是就有了FastCGI。

  一般意况下, FastCGI 的一切工作流程如下所述。

  ( 1 ) Web Server 启动时载入 法斯特CGI 进程管理器( IIS ISAPI 或 Apache
Module ) 。

  ( 2 )Fast(Fast)CGI 进程管理器自身起先化,启动两个 CGI 进程并等待来自 Web
服务器的连接 。

  ( 3 )当客户端请求到达 Web Server 时, FastCGI
进程管理器选用并连接到一个 法斯特(Fast)CGI进程 。 Web 服务器将 CGI
环境变量和正式输入发送到 Fast(Fast)CGI 进程 。

  ( 4) Fast(Fast)CGI 子进程完成处理后将规范输出和错误音信从同一连接重返 Web
Server。当Fast(Fast)CGI 子进程关闭连接时,请求便被报告处理到位 。 Fast(Fast)CGI
进程接着等待并处理来自法斯特(Fast)CGI 进程管理器(运行在 Web
服务器中)的下一个连接 。

三、tinyhttpd解析

  关于tinyhttpd的代码解析的博客太多了,流程跟注释都讲述的很详细,随便搜个tinyhttpd解析就有成百上千博客出现,这里依旧写一下谈得来在看这份源码时缺乏的知识点,因为自己几乎从不linux下编程的经验,所以对linux下用的Glib库调用不太熟稔,TCP协议栈也是自个儿只看过过轻量级Lwip的源码。

  1.bind函数当传入的port为0时是会随便分配一个端口号,所以tinyhttpd中才会有显示随机的端口号,getsockname函数获取套接字的地点把动态分配的端口号值取出。

  图片 2图片 3

  2.int stat(const char *file_name, struct stat
*buf);通过文件名filename获取文件信息,并保存在buf所指的构造体stat中,S_IXUSR:文件所有者具可实施权限,S_IXGRP:用户组具可实施权限,S_IXOTH:其他用户具可读取权限。

图片 4

  3.int pipe(int filedes[2]);

  重回值:成功,再次回到0,否则重返-1。参数数组包含pipe使用的多少个文本的讲述符。fd[0]:读管道,fd[1]:写管道。

  必须在fork()中调用pipe(),否则子进程不会延续文件讲述符。六个过程不共享祖先进程,就不能够动用pipe。不过足以选拔命名管道。

  pipe(cgi_output)执行成功后,cgi_output[0]:读通道
cgi_output[1]:写通道

  图片 5

   int dup2(int oldfd,int newfd);函数的效力是复制文件讲述符。

  4.fork函数,创设一个子进程,fork函数之后的一部分由在fork函数执行完毕后,即使创设新历程成功,则产出多少个经过,一个是子进程,一个是父进程。在子进程中,fork函数再次来到0,在父进程中,fork重回新创建子进程的过程ID,有时光再看fork源码是如何兑现的。

  5.execl函数实施,第一参数path字符指针所指向要实践的公文路径,前边跟着可变参数,这里说一些由于GCC使用AAPCS规范,可变参数的兑现小于多少个的话是从r0-r3拿到,大于五个的话就要从栈中获取参数。 

  6.pid_t waitpid(pid_t pid, int * status, int
options);会临时停止如今历程的实施, 直到有信号来到或子进程截至. 

  在编制博客边看tinyhttpd,近日温馨的不够明亮的函数就地方多少个,有空再看看它们的源码实现。