基于HTTP协议实现小型的web服务器
HTTP是通过TCP实现的可靠的网络传输.下面是一个完整的HTTP过渡到TCP实现客户端与服务器的交互:1.当客户端执行网络请求的时候
,会从URL地址中解析出URL的主机名,并将主机地址转换成IP.2.从URL解析出服务器的所用端口号3.客户端用TCP连接服务器4.连接
成功后,获取输出流,并将数据以报文的形式传递给服务器.5.当服务器接受到数据之后,进行判断和解析码,并回送一条响应报文.
6.客户端从输入流中获取报文,并解析.7.最后关闭网络的连接
常见HTTP请求服务器的方式:
1.GET请求
作用:获取服务器的某个资源,或者说是告诉服务器,我想查询的信息.
特点:明文传输(直接将传送给服务器的数据写在URL上).
常用:跳转到另一个网站,网站名就是GET传输,然后向服务器请求获取该网站.
2.POST请求
作用:向服务器传递数据,一般用来提交HTML表单时使用,服务器处理这些数据.
特点:表单上传(写入的数据,不显示在URL上)
常用:注册用户名,密码.传送给服务器处理.
3.PUT请求
作用:向服务器写入资源,在服务器创建一个文本,然后将Client传输数据给service.不过一个是写在
URL上,一个是写在form表单上. 然后servie端根据这些上传的数据进行处理.
4.DELETE请求
作用:从服务器中删除资源.(无法保证是否被删除,HTTP规范允许不通知客户端拒绝该请求)
5.HEAD请求
作用:让Service只返回报文的头部. client端根据报文的头部,能够判断(数据域的信息,判断该报文是否存在数据等)
6.OPTION请求
作用:询问服务器支持哪些方法(比如POST,GET,OPTION方法)
HTTP协议的主要特点:
1.支持客户/服务器模式
2.简单快捷:客户向服务器发送请求服务时,只需要传送请求方法和路径,请求方法常用的有GET,POST,DELETE,PUT,HEAD.OPTION.
每种方法规定了客户与服务器联系的类型的不同,由于HTTP协议简单,使得HTTP服务器的规模小,因此通信速度很快.
3.灵活:HTTP允许传输任意类型的数据对象,正在传输的类型由content-Type加以标记.
4.无连接:无连接的含义是限制每次链接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,既断开连接,采
用这种方式可以节省传输时间,请求应答机制就会断开.
5.无状态:HTTP协议是无状态协议,无状态是指协议对于事物处理没有记忆能力
这里我想补充一点东西,平日里我们在登陆了一个网页的时候,短时间内重新打开这个网页的时候就会发现自动登陆了,但是HTTP应
该是无链接的啊.这里其实是为了让用户有更好的上网体验做出的优化,你的客户端本地通常会有一个cookie文件,他保存的是你的基
本信息,当你第一次访问一个需要登录的网站时,其实是将你的cookie发送了过去,然后服务器提取出有用的信息进行登录并且针对
客户端短时间内生产一个session id. 用来标识唯一的一个用户,然后你的session id被写入你的cookie文件中,下次当你访问网页
的时候直接在你的cookie当中识别出session id进行登录. 看起来很方便,但是它对用户信息安全是有隐患的,当你通过网页登录
qq时,然后呢,你被一些不可描述的钓鱼网站吸引进去了,你点击了这个网站,这个时候你的本地cookie文件发送到该网站服务器
当中! 但是由于你刚刚登陆了qq,所以你的用户名和密码都在cookie文件当中,这个时候你就会被别人盗取你的qq号,这是一个很简
单的例子! 所以网上尽量不要乱点什么不可描述的网站.
关于URL,既同一资源定位符,每个网页都对应一个URL地址,具有全球唯一性. 它包含的信息之处文件的位置以及浏览器应该如何处
理它,一个完整的URL包括协议类型,主机类型,路径和文件名.
http协议的URL格式: http://host[:port][abs_path] => 协议://主机域名(ip地址)[端口号][资源路径]
我们的GET方法使用的是带参数的URL,既传递的参数会使用?连接在资源路径的后边; POST方法使用的是不带参数的URL,它的参数是
通过http请求正文传递给服务器的. 下图是关于HTTP的请求和响应模式:
响应报头中的状态码和状态码描述,举个例子,当请求的资源不存在的时,会收到"404 NotFound"的页面,404就是状态码,
"NotFound"就是状态码描述,既请求的文件不存在. 现在HTTP的概念差不多说完了. 那我们开始搭建我们的服务器吧.
HTTP服务器的实现思路
1.面向链接:http协议是基于TCP通信协议,因此实现web服务器的第一步至少要能实现两个主机不同进程之间的TCP通信,并且需要
解决高并发问题所以这里推荐使用多线程服务器来构建,每次创建出来一个新线程出来的时候将线程分离,然后让这个新线程去处
理这个请求.
2.分析出请求行:当服务器收到请求后,首先你需要知道的是HTTP服务器版本和请求方法,web服务器是要支持cgi的,但请求方
法不同可能cgi也不同,我们服务器比较简单所以只处理GET和POST方法)
3.判断cgi模式:如果方法为GET方法不带参那么非cgi模式,如果为GET方法并且带参,或者为POST方法那么为cgi模式.
4.响应客户端:这个时候我们已经知道了方法以及是否为cgi模式,然后开始读取URL,这里有一个细节非cig模式 请求参数会跟
在URL当中,如果cgi模式的话,参数在消息正文中,然后我们读取到路径,判断路径当中资源是否存在,如果存在判断这个资源
是一个目录,普通文件还是一个可执行程序
这里分情况如果是cgi模式,直接进入cgi内部运行;只要是POST方法就需要支持cgi,直接进入cgi函数内部运行.
如果是非cgi模式时一定是GET方法并且没有参数,此时进入echo_www()函数内部即可,该函数会将所请求的资源以html的格式返回给
浏览器.
接下来是解释运行cgi模式,首先服务器要从浏览器读取参数,然后创建出来一个子进程去执行cgi部分的可执行资源,父进程通过环
境变量的方式传递给子进程,子进程运行完成之后呢,将结果交给父进程,父进程再将数据输出给浏览器. 所以父进程在这个例子
当中就向是一个中介,只进行参数和结果的转交实际上并不会执行任何资源,因此将子进程的输入输出文件描述符重定向,就可以让
子进程直接与浏览器"联系".
父进程做的事情
1.创建两个管道,并关闭相应的文件描述符
2.POST方法:继续读取数据,直到读完POST的参数部分GET方法:直接从子进程读取结果
3.将数据和方法全部交给子进程后等待子进程的结果
子进程做的事情
1.关闭管道适当的文件描述符
2.对标准输入输出进行重定向
3.通过环境变量传递参数
4.进行exec程序替换
下图帮助我们理解cgi模式运行过程:
这里就是这个项目的主要思想,我们需要做的就是就是以上说到的,接下来使用代码将他们实现即可. 在编写代码当中我遇到了相
当多的问题:
1.图片加载不出来: 因为我使用的是虚拟机,然后从windows将图片拖进来,让图片这个文件拥有了可执行权限,这里我还有及时
发现,所以每次程序运行的过程中加载不出来图片,以为图片拥有可执行权限后,本来应该是使用GET方法直接将图片以html形式
返回给浏览器,但是这里走了cgi的方法,所以出现了错误 我们应该让图片文件去除掉可执行权限.
2.关闭防火墙 打开桥接模式 可以让你在外部浏览器测试. 这是网络编程最开始就应该做的! 一定要提前准备好.
3.执行POST方法的时候因为没有进行drop_header操作,读取参数错误,导致结果错误. POST方法的参数在有效载荷头部存储.
4.能够显示图片,但是显示不完整(原因:echo_www中,期望读取一行信息的line值太小,不能存下一个图片)