[计算机网络]httpserver--如何解析HTTP请求报文

这个http server的实现源代码我放在了我的github上,有兴趣的话可以点击查看哦。

在上一篇文章中,讲述了如何编写一个最简单的server,但该程序只是接受到请求之后马上返回响应,实在不能更简单。在正常的开发中,应该根据不同的请求做出不同的响应。要做到上述的功能,首先要解析客户端发来的请求报文。

报文在不同的上下文情景下有不同的理解,本文所说的报文都是在HTTP上下文中描述的名词。

HTTP报文是什么

在HTTP程序中,报文就是HTTP用来搬运东西的包裹,也可以理解为程序之间传递信息时发送的数据块。这些数据块以一些文本形式的元信息开头,这些信息描述了报文的内容和含义,后面跟着可选的数据部分。

报文的流动

HTTP使用属于流入和流出来描述报文的传递方向。HTTP报文会像合水一样流动。不管时请求报文还是响应报文,都会向下游流动,所有报文的发送者都在接受者的上游。下图展示了报文向下游流动的例子。

报文向下游流动

报文的组成

报文由三个部分组成:

  • 对报文进行描述的起始行

  • 包含属性的首部块

  • 可选的、包含数据的主体部分

起始行和首部是由行分隔的ASCII文本。每行都以一个由两个字符(回车符--ASCII码13和换行符--ASCII码10)组成的行终止序列结束。可以写做CRLF

尽管规范说明应该用CRLF来表示行终止,但稳健的应用程序也应该接受单个换行作为行的终止。笔者仅支持以CRLF换行的解析,因为我觉得既然有了规范,那就需要遵循,遵循相同的协议的程序才能互相通信。

实体是一个可选的数据块。与起始行和首部不同的是,主体中可以包含主体或二进制数据,也可以为空(比如仅仅GET一个页面或文件)。

下面来看看报文的语法的格式和规则。

报文的语法

请求报文的语法:

<method> <request-URL> <version>
<headers><entity-body>

响应报文的语法:

<version> <status-code> <reason-phrase>
<headers><entity-body>

method,方法

客户端希望服务器对资源执行的操作。比如GET、POST

request-URL,请求URL

请求资源,或者URL路径组件的完整URL。

version,版本

报文所使用的HTTP版本。格式:HTTP/<major>.<minor>。其中major(主要版本号)和minor(次要版本号)都是整数。

status-code,状态码

描述请求过程所发生的情况的数字。

reason-phrase,原因短语

数字状态码的文字描述版本。

headers,首部

每个首部包含一个名字,后面跟着一个冒号(:),然后是一个可选的空格,接着是一个值,最后是一个CRLF。可以有零个或多个首部。首部由一个CRLF结束,表示首部结束和实体主体开始。

entity-body,实体的主体部分

包含一个由任意数据组成的数据块。可以没有,此时是以一个CRLF结束。

请求行

请求报文的起始行称为请求行。所有的HTTP报文都以一行起始行作为开始。请求行包含一个方法和一个请求URL以及HTTP的版本三个字段。每个字段都以空格分隔。

比如:GET / HTTP/1.1

请求方法为GET,请求URL为/,HTTP版本为HTTP/1.1。

响应行

响应报文的起始行称为响应行。响应行包含HTTP版本、数字状态码以及描述操作状态的文本形式的原因短语。三个字段也是以空格分隔。

比如:HTTP/1.1 200 OK

HTTP版本为HTTP/1.1,数字状态码是200,原因短语是OK。表示请求成功。

首部

首部是是包含在请求和响应报文的一些附加信息。本质上,他们只是一些键值对的列表。

比如:Content-Length: 19

表示返回内容长度为19。

实体的主体部分

简单地说,这部分就是HTTP要传输的内容。

解析请求报文

了解了报文是如何组成和各部分代表的内容之后,就对如何解析请求报文心里有数了。

核心代码

    /* 解析请求行 */int parse_start_line(int sockfd, char *recv_buf, req_pack *rp){char *p = recv_buf;char *ch = p;int i = 0;enum parts { method, url, ver } req_part = method;char *method_str;char *url_str;char *ver_str;int k = 0;if (*ch < 'A' || *ch > 'Z') {return -1;}while (*ch != CR) {if (*ch != BLANK) {k++;} else if (req_part == method) {method_str = (char *)malloc(k * sizeof(char *));memset(method_str, 0, sizeof(char *));strncpy(method_str, recv_buf, k);k = 0;req_part = url;} else if (req_part == url) {url_str = (char *)malloc(k * sizeof(char *));memset(url_str, 0, sizeof(char *));strncpy(url_str, recv_buf + strlen(method_str) + 1, k);k = 0;req_part = ver;}ch++;i++;}if (req_part == url) {if (k != 0) {url_str = (char *)malloc(k * sizeof(char));memset(url_str, 0, sizeof(char));strncpy(url_str, recv_buf + strlen(method_str) + 1, k);k = 0;} else {return -1;}}if (k == 0) {ver_str = (char *)malloc(8 * sizeof(char));memset(ver_str, 0, sizeof(char));strcpy(ver_str, "HTTP/1.1");} else {ver_str = (char *)malloc(k * sizeof(char));memset(ver_str, 0, sizeof(char));strncpy(ver_str,recv_buf + strlen(method_str) + strlen(url_str) + 2, k);}rp->method = method_str;rp->url = url_str;rp->version = ver_str;return (i + 2);}/* 解析首部字段 */int parse_header(int sockfd, char *recv_buf, header headers[]){char *p = recv_buf;char *ch = p;int i = 0;int k = 0;int v = 0;int h_i = 0;bool is_newline = false;char *key_str;char *value_str;header *tmp_header = (header *)malloc(sizeof(header *));memset(tmp_header, 0, sizeof(header));while (1) {if (*ch == CR && *(ch + 1) == LF) {break;}while (*ch != COLON) {ch++;i++;k++;}if (*ch == COLON) {key_str = (char *)malloc(k * sizeof(char *));memset(key_str, 0, sizeof(char *));strncpy(key_str, recv_buf + i - k, k);k = 0;ch++;i++;}while (*ch != CR) {ch++;i++;v++;}if (*ch == CR) {value_str = (char *)malloc(v * sizeof(char *));memset(value_str, 0, sizeof(char *));strncpy(value_str, recv_buf + i - v, v);v = 0;i++;ch++;}i++;ch++;headers[h_i].key = key_str;headers[h_i].value = value_str;h_i++;}return (i + 2);}

解析思想

遍历recv接受到的请求字符串,检查是否遇到回车符r判断一行数据。

对于起始行,检查是否遇到空格分隔不同的字段;对于首部,检查是否遇到冒号分隔键值对的字段值;对于实体的主体部分,则先判断是否遇到CRLF字符串,然后将剩余内容全部作为实体的主体部分。

返回值是告知程序下一次遍历的起始位置。

如果遇到非法请求行则返回400的响应。

总结

解析报文的过程就是遵循HTTP协议规定的内容去解析报文,获取报文包含的信息。

由于基础知识较薄弱,代码还有很多错误以及很多地方需要优化。如果有看到错误的地方或有其它建议望各位大侠不吝赐教。^_^

这个http server的实现源代码我放在了我的github上,有兴趣的话可以点击查看哦。

原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

如果本文对你有帮助,请点下推荐吧,谢谢^_^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/542291.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

英特尔核芯显卡控制面板没有了_核显和独显、集成显卡有什么区别

集成显卡&#xff1a;一般不带有显存&#xff0c;而是使用系统的一部分主内bai存作为显存&#xff0c;具体的数量一般是系统根据需要自动动态调整的。显然&#xff0c;如果使用集成显卡运行需要大量占用内存的空间&#xff0c;对整个系统的影响会比较明显&#xff0c;此外系统内…

徐州初中计算机学校排名2015,徐州初中学校排名,徐州重点初中排名详细榜单

2018年徐州初中学校排名,徐州重点初中排名详细榜单孩子小升初&#xff0c;几乎所有的家长都会陷入纠结&#xff0c;都想为孩子选择一所“好学校”&#xff0c;在择校过程中&#xff0c;家长们总想知道徐州初中学校排名以及徐州重点初中排名详细榜单&#xff0c;但这里小编提醒一…

分布式计算 MapReduce与yarn工作机制

一、第一代hadoop组成与结构第一代Hadoop&#xff0c;由分布式存储系统HDFS和分布式计算框架MapReduce组成&#xff0c;其中&#xff0c;HDFS由一个NameNode和多个DataNode组成&#xff0c;MapReduce由一个JobTracker和多个TaskTracker组成&#xff0c;对应Hadoop版本为Hadoop …

计算机无法上无线网络连接到internet,电脑连接不上无线网络,教您怎么解决电脑连接不上无线网络...

小编家的那位笔记本姐姐之前可能是受委屈了&#xff0c;一个一个的电脑问题丢出来给我解决。之前有段时间总是出现电脑连接不上无线网络的问题&#xff0c;弄得那短时间天天都在想办法是解决。现在&#xff0c;我就要将这种解决方法分享给你们&#xff0c;让你们在遇到这个问题…

格兰杰因果关系检验_混频(mixed frequency)数据的格兰杰因果(Grange causality)检验及其Matlab实现...

格兰杰和格兰杰因果网络搜到的Grange大神标准照格兰杰1934年9月出生于英国威尔士的斯旺西&#xff0c;早期就读于诺丁汉大学&#xff0c;接受当时英国第一个经济学数学双学位教育&#xff0c;1955年留校任教&#xff0c;1957年在天文学杂志上他发表了第一篇论文&#xff1a;“关…

后台窗口截图_万人拥捧的截图软件来啦!让你的工作效率提升不止一倍!

文章来自微信公众号&#xff1a;小七有料直接进入正题&#xff0c;今天不野给大家分享两款截图软件——Snipaste和FastStone Capture&#xff0c;前者与其说是一个截图软件&#xff0c;我更愿意称之为贴图软件。两者都在工作中很大程度提高了我的效率&#xff0c;也简便化了我很…

ibm nvidia 超级计算机,IBM,Nvidia和美国能源部组成一个超级计算机超级团队

CNET技术信息网7月15日国际报道: IBM将与Nvidia和美国能源部合作建立两个新的杰出超级计算机中心. 这项合作的工作主要集中在两个方面&#xff0c;一个是确保应用程序可以充分利用超级计算机的强大性能&#xff0c;另一个是收集开发人员&#xff0c;工程师和科学家的反馈.这两个…

华为p40论坛_华为高端旗舰继续发力!麒麟990 5G+超感知三摄,256GB降价799元

小米10、一加8&#xff0c;vivo NEX3S等高性能旗舰产品现已在市场上发售。其中&#xff0c;5G旗舰华为P40也在销售团队中&#xff0c;并且最近成为最受欢迎的旗舰产品。由于华为P40高端版从799元跌至4189元&#xff0c;消费者可以以不到800元的价格购买低价高性能旗舰产品&…

移动端类似IOS的滚动年月控件(需要jQuery和iScroll)

http://www.cnblogs.com/ccblogs/p/5260949.html 一. 效果图 二. 功能介绍 支持滚动和点击选择年月。&#xff08;目前只支持设置年月的最大最小值&#xff0c;不支持整体的最大最小值&#xff09; 三. 代码 1. 在你的html中添加如下代码&#xff1a; 直接加载<body>里面…

css 横向滚动隐藏滚动条_使用CSS滚动时如何隐藏滚动条?

css 横向滚动隐藏滚动条Introduction: 介绍&#xff1a; It is always nice to have a responsive website or web page, to create such websites or web pages we have to make use of our developing skills to a great extent to bring about the functionality as well a…

DrawerLayout侧滑详解

前面我们说了自定义侧滑菜单&#xff0c;也说了SlidingMenu的使用&#xff0c;这一节我们再来说下DrawerLayout。DrawerLayout是Support Library包中实现了侧滑菜单效果的控件&#xff0c;可以说DrawerLayout是因为第三方控件如SlidingMenu等出现之后&#xff0c;google借鉴而出…

华为笔记本计算机在哪,新一代华为MateBook 的机会在哪里?

2017年5月23日 在德国柏林&#xff0c;华为正式面向全球消费者发布了MateBook系列新品——13英寸灵动商务笔记本MateBook X、12英寸时尚二合一笔记本MateBook E及15.6英寸商务影音笔记本MateBook D。今天笔记本市场似乎是一个比较稳定的市场&#xff0c;笔记本的销量增长不快&a…

kaggle计算机视觉比赛技巧,9. 计算机视觉 - 9.12. 实战Kaggle比赛:图像分类(CIFAR-10) - 《动手学深度学习》 - 书栈网 · BookStack...

9.12. 实战Kaggle比赛&#xff1a;图像分类(CIFAR-10)到目前为止&#xff0c;我们一直在用Gluon的data包直接获取NDArray格式的图像数据集。然而&#xff0c;实际中的图像数据集往往是以图像文件的形式存在的。在本节中&#xff0c;我们将从原始的图像文件开始&#xff0c;一步…

qthread中获取当前优先级_Linux中强大的top命令

top命令算是最直观、好用的查看服务器负载的命令了。它实时动态刷新显示服务器状态信息&#xff0c;且可以通过交互式命令自定义显示内容&#xff0c;非常强大。在终端中输入top&#xff0c;回车后会显示如下内容&#xff1a;top - 21:48:39 up 8:57, 2 users, load average: 0…

snmp 获得硬件信息_计算机网络基础课程—简单网络管理协议(SNMP)

简单网络管理协议(Simple Network Management Protocol)•除了提供网络层服务的协议和使用那些服务的应用程序&#xff0c;因特网还需要运行一些让管理员进行设备管理、调试问题、控制路由、监测机器状态的软件。这种行为称为网络管理。••随着网络技术的飞速发展&#xff0c;…

僵尸毁灭工程 服务器已停止运行,《僵尸毁灭工程》steam is not enabled错误解决方法...

Steam 上面的 Project Zomboid 因为带有 VAC 所以建服开服需要 Steam服务器认证&#xff0c;这也是出现 steam is not enabled 错误主要原因&#xff0c;也是无法和普通零售正版所建的服务器联机的罪魁祸首。分两种情况(下面 Project Zomboid 均简称PZ)&#xff1a;1、steam版P…

spring boot 1.4默认使用 hibernate validator

spring boot 1.4默认使用 hibernate validator 5.2.4 Final实现校验功能。hibernate validator 5.2.4 Final是JSR 349 Bean Validation 1.1的具体实现。 How to disable Hibernate validation in a Spring Boot project As [M. Deinum] mentioned in a comment on my original …

服务器修改开机启动项,启动项设置_服务器开机启动项

最近很多观众老爷在苦觅关于启动项设置的解答&#xff0c;今天钦编为大家综合5条解答来给大家解开疑惑&#xff01; 有98%玩家认为启动项设置_服务器开机启动项值得一读&#xff01;启动项设置1.如何在bios设置硬盘为第一启动项详细步骤根据BIOS分类的不同操作不同&#xff1a;…

字符串查找字符出现次数_查找字符串作为子序列出现的次数

字符串查找字符出现次数Description: 描述&#xff1a; Its a popular interview question based of dynamic programming which has been already featured in Accolite, Amazon. 这是一个流行的基于动态编程的面试问题&#xff0c;已经在亚马逊的Accolite中得到了体现。 Pr…

Ubuntu 忘记密码的处理方法

Ubuntu系统启动时选择recovery mode&#xff0c;也就是恢复模式。接着选择Drop to root shell prompt ,也就是获取root权限。输入命令查看用户名 cat /etc/shadow &#xff0c;$号前面的是用户名输入命令&#xff1a;passwd "用户名" 回车就可以输入新密码了转载于:…