阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

想要创建一个基于TCP实现的http服务器,应该怎么做?

90次阅读
没有评论

共计 2728 个字符,预计需要花费 7 分钟才能阅读完成。

咱们先了解一下这个项目最终能到达的一个方针,然后以这个来进行项目的剖析:
1、实现最基本的 HTTP/1.0 版本的 web 服务器,客户端能够使用 GET、POST 方法请求资源
2、服务器将客户请求的资源以 html 页面的形似呈现,并能够进行差错处理(如:客户请求的资源不存在时,服务器能够返回一个 404 的页面)
3、服务器能进行简单的 cgi 运行。比如当客户在表单中输入数据后,服务器能够将运行结果返回个客户
4、能够通过页面对数据库进行操作,如增删查改等操作

一、http 服务器实现的基本框架

  • 关于 HTTP 协议
    即超文本传输协议,是互联网上应用最广泛的网络协议。它是应用层的协议,底层是基于 TCP 通信的。HTTP 协议的工作过程:客户通过浏览器向服务器发送文档请求,浏览器将请求的资源回应给浏览器,然后关闭连接。即:连接 -> 请求 -> 响应 -> 关闭连接。
  • 关于 URL
    即统一资源定位符,每个网页都对应一个 URL 地址(俗称网址),具有全球唯一性。它包含的信息指出文件的位置以及浏览器应该怎么处理它。一个完整的 URL 包括协议类型、主机类型、路径和文件名。
    http 协议的 URL 格式:http: //host[:port][abs_path],http 表示使用 http 协议来进行资源定位;host 是主机域名;port 是端口号,一般有默认的;abs_path 代表资源的路径。
    这里我主要介绍项目中涉及的 URL 的两种格式—URL 带参数和不带参数的。
    想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?
    GET 方法使用的是带参数的 URL,即传递的参数会使用?连接在资源路径后边;POST 方法使用的是不带参数的 URL,它的参数是通过 http 请求报头中的请求消息体传递给服务器的。
  • 关于 HTTP 的请求与响应格式
    想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?
    响应报头中的状态码和状态码描述,例如:当请求的资源不存在时,会收到“404 NotFound”的页面,404 就是状态码,“NotFound”就是状态码描述,即请求的文件不存在。

二、服务器实现的基本思路

1、http 协议是基于 TCP 通信的协议,因此,实现 web 服务器的第一步至少要能实现两个主机不同进程之间的 TCP 通信。
2、接下来的部分就是比较主要的处理逻辑了,当服务器收到请求后,首先应该分析请求方法(因为 web 服务器是要支持 cgi 的,但请求方法不同处理 cgi 也不同,这里我们只处理 GET 和 POST 方法)。
3、当方法确定后,应该拿到请求的 URL,这一步是为了我们后边能处理 GET 和 POST 方法的 cgi(GET 和 POST 的参数位置不同,GET 的参数在 URL 中,POST 的参数在请求正文中)
4、判断资源是否存在,如果存在,判断这个资源是一个目录、普通文件还是一个可执行程序。之前几步我们已经提取到 URL 以及参数。GET 方法:如果没有参数,就直接将请求的资源返回(即进入非 cgi 模式运行);否则,进入 cgi 模式内部运行;只要是 POST 方法就需要支持 cgi:直接进入 cgi 函数内部运行。

非 cgi 模式:
进入非 cgi 模式时一定是 GET 方法且没有参数,此时进入 echo_www()函数内部即可,该函数会将所请求的资源以 html 的格式返回给浏览器。

cgi 模式:
想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?
上述这张图描述了运行 cgi 时的过程,首先服务器要从浏览器上读取参数,然后需要 fork 出一个子进程进行 cgi 部分的处理,父进程通过环境变量的方式将参数转交给子进程,子进程运行完成后,将结果交给父进程,父进程再将数据输出给浏览器。在这个过程中可以将父进程看作一个所谓的中间量,只进行了参数的转交,因此可以将子进程的输入输出文件描述符进行重定向,即子进程直接与浏览器“联系”。

下面总结出父子进程内部各自需要干的事情:
想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?

三、错误处理

错误处理这部分的实现可以参考 echo_www()函数,但需要改变响应的消息报头的格式,即改变状态码,状态码描述,以及返回的页面。例如当请求的资源不存在时,服务器需要返回给浏览器一个默认的 404 页面,告诉客户请求的资源不存在。效果如图:
想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?

四、项目文件

 想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?
目录:
cgi:运行 cgi 部分的实现代码
conf:配置文件,存放需要绑定的服务器的 ip 和 port
log:shell 的日志文件以及 http 错误处理的日志文件
lib:MySQL 需要的 lib 库
sql_client:mysql 部分的 API 及 CGI 实现
wwwroot:web 服务器工作的根目录,包含各种资源页面(例如默认的 index.html 页面,差错处理的 404 页面),以及执行 cgi 的可执行程序

文件:
configure.sh:sheel 脚本,运行该 shell 脚本后需要自动生成 Makefile 文件
http_ctl.sh:服务器控制脚本,需要实现服务器的启动、暂停以及重新启动
httpd.pid:与 http_ctl.sh 配合使用。如果把服务器变成守护进程在后台运行,重新启动时就需要检测服务器是否启动,该文件存放服务器启动以后的进程 id
httpd.h:服务器的方法声明
httpd.c:方法实现
main.c:服务器的主逻辑

五、实现结果

请求资源存在:
想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?

运行 cgi 后:
想要创建一个基于 TCP 实现的 http 服务器,应该怎么做? 想要创建一个基于 TCP 实现的 http 服务器,应该怎么做? 想要创建一个基于 TCP 实现的 http 服务器,应该怎么做? 想要创建一个基于 TCP 实现的 http 服务器,应该怎么做? 想要创建一个基于 TCP 实现的 http 服务器,应该怎么做? 想要创建一个基于 TCP 实现的 http 服务器,应该怎么做? 想要创建一个基于 TCP 实现的 http 服务器,应该怎么做?

六、源码:

https://github.com/lybb/Linux/tree/master/httpd

附:
这里是我遇到的一些问题,粘出来,也可能是你遇到的问题:
1、本地环回测试 ok,Linux 下的浏览器测试也可以,但不能接外部的浏览器访问(没有设置桥接模式)嗯~ 要是在外部浏览器测试的话千万别忘记关闭防火墙
2、服务器应答时,没有将 html 格式的页面发送,而是将底层的实现代码展示在浏览器,并且在调试时将本来要打印的调试信息会打印到网页上(在回应空行时将 send 期望发送的数值写的太大,本来只需要发送两个字节的内容)
解决:先检查代码,思路正确,在容易出现问题的地方加入调试信息,最后将问题定位在 echo_www()函数内
3、不能显示图片(这个问题是没有将所有发送的情况考虑完全,只考虑到目录、可执行程序,但没有考虑到如果请求的是一个路径明确的普通文件)
解决:测试请求一个路径明确的 test.html 文件,加入调试信息,将问题定位在:如果请求的资源存在,应该如何处理。对于普通文件,找到后并回显给浏览器;如果是目录,应答的是默认页面;如果是可执行程序,执行后返回结果
4、能显示图片后,但显示的不完整(原因:echo_www 中,期望读取一行信息的 line 值太小,不能存下一张图片)
5、运转 cgi 模式时,每次提交数据并进行 submit 后都会主动出现提示下载的页面
因素:在响应报头中,将 Content-Type 中的”text”写成”test”。而浏览器关于不能辨认或解析的实体,都会提示用户下载。

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-12-03发表,共计2728字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中