[计算机网络]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,一经查实,立即删除!

相关文章

python字典副本_如何复制字典并仅在Python中编辑副本?

python字典副本Python never implicitly copies the dictionary or any objects. So, while we set dict2 dict1, were making them refer to the same dictionary object. Hence, even when we mutate the dictionary, all the references made to it, keep referring to the…

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

集成显卡&#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 …

c++ stl队列初始化_创建一个向量,并将其像C ++ STL中的数组一样初始化

c stl队列初始化向量是什么&#xff1f; (What is the vector?) Vector is a container in C STL, it is used to represent array and its size can be changed. Vector是C STL中的一个容器&#xff0c;用于表示数组&#xff0c;并且其大小可以更改。 Read more: C STL Vec…

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

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

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

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

C#Convert.ToInt32(byte)方法-将字节值转换为int

C&#xff03;Convert.ToInt32(byte)方法 (C# Convert.ToInt32(byte) Method) Convert.ToInt32(byte) Method is used to convert a specific byte value to its equivalent integer (int 32 signed number). Convert.ToInt32(byte)方法用于将特定的字节值转换为其等效的整数(i…

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

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

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

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

C#Convert.ToInt32(char)方法-将char值转换为int

C&#xff03;Convert.ToInt32(char)方法 (C# Convert.ToInt32(char) Method) Convert.ToInt32(char) Method is used to convert a specific char value to its equivalent integer (int 32 signed number) (It can also be known as ASCII value). Convert.ToInt32(char)方法…

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

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

计算机基础.doc,大学生计算机基础.doc

WORD格式 整理分享范文范例 参考指导电子计算机的诞生1计算机的发展经历了4个时代&#xff0c;各个时代划分的原则是根据( )。A、计算机所采用的电子器件B、计算机的运算速度C、程序设计语言D、计算机的存储量正确答案&#xff1a;A?2世界上第一台电子计算机诞生于( )年。A、1…

移动端类似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…

python 字符串 变量_检查变量是否为字符串的Python程序

python 字符串 变量Python | 检查变量是否为字符串 (Python | Check if a variable is a string) To check whether a defined variable is a string type or not, we can use two functions which are Python library functions, 要检查定义的变量是否为字符串类型&#xff0c…

mysql shell

mysql 查询10分钟以内的数据:select *from t_agent where int_last_login>CURRENT_TIMESTAMP - INTERVAL 10 MINUTE; mysql关联多表进行update更新操作UPDATE TrackINNER JOIN MVON Track.trkidMV.mvidSET Track.is_showMV.is_showWHERE trkid<6等同于UPDATE Track,MVSET…

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

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