LwIP应用开发笔记之七:LwIP无操作系统HTTP服务器
前面我们实现了TCP服务器和客户端的简单应用,接下来我们实现一个基于TCP协议的应用协议,那就是HTTP超文本传输协议
1、 HTTP协议简介
超文本传输协议(Hyper Text Transfer Protocol),简称HTTP,是一种基于TCP的应用层协议,也是目前为止最为流行的应用层协议之一,可以说HTTP协议是万维网的基石。
HTTP是一种客户端请求、服务器应答式的应用层传输协议,也就是说服务器端是不可能主动向客户端发送数据的。在网络正常的情况下请求和响应都是一一对应的。而这个请求和响应也就是后端开发人员经常看到的Request和Response。
首先,我们来看客户器端的请求,HTTP请求报文由请求行、请求头、空白行以及请求体组成。其报文格式如下:
我们来说一说请求行,它由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。需要理解的是请求方法,HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT几种。先对常用的几种说明如下:
- GET方法,意思是获取URL指定的资源,这个请求方式是最简单的也是最常用的。使用GET 方法时,可以将请求参数和对应的值附加在 URI 后面,利用一个问号(“?”)将资源的URI和请求参数隔开,参数之间使用与符号(“&”)隔开,因此传递参数长度也受到了限制,而且与隐私相关的信息也直接暴露在URI中。比如/index.jsp?username=holmofy&password=123123
- HEAD方法,与GET用法相同,但没有响应体,使用场合没有GET多。比如下载前使用HEAD发送请求,通过ContentLength响应字段,来了解网络资源的大小;或者通过LastModified响应字段来判断本地缓存资源是否要更新。
- POST方法,一般用提交信息或数据,请求服务器进行处理(例如提交表单或者上传文件)。表单使用POST相对GET来说还是比较隐秘的,而且GET的URL有长度限制,而上传大文件就必须要使用POST了。
- OPTIONS方法,该方法用于请求服务器告知其支持哪些其他的功能和方法。通过OPTIONS 方法,可以询问服务器具体支持哪些方法,或者服务器会使用什么样的方法来处理一些特殊资源。可以说这是一个探测性的方法,客户端通过该方法可以在不访问服务器上实际资源的情况下就知道处理该资源的最优方式。这个选项在跨域HTTP请求的情况出现的比较多,这里有一篇关于跨域请求的文章,其中有一张图很好的解释了什么是跨域HTTP请求。
客户端发出HTTP请求,服务端接收后,会向客户端发送响应信息。所以接下来,我们来看看服务器端的响应报文。HTTP响应报文由响应行、响应头、空白行以及响应体组成。其报文格式如下:
在响应报文中,非常重要的就是响应行,其中响应行中最重要的就是HTTP的状态码。HTTP协议中状态码有三位数字组成,第一位数字定义了响应的类别,有以下五种:
- 1XX:信息提示。表示请求已被服务器接受,但需要继续处理,范围为100~101。
- 2XX:请求成功。服务器成功处理了请求。范围为200~206。
- 3XX:客户端重定向。重定向状态码用于告诉客户端浏览器,它们访问的资源已被移动,并告诉客户端新的资源位置。客户端收到重定向会重新对新资源发起请求。范围为300~305。
- 4XX:客户端信息错误。客户端可能发送了服务器无法处理的东西,比如请求的格式错误,或者请求了一个不存在的资源。范围为400~415。
- 5XX:服务器出错。客户端发送了有效的请求,但是服务器自身出现错误,比如Web程序运行出错。范围是500~505。
我们开发过程有一些状态码比较常见,我们对其简单说明如下:
2、 HTTP服务器端的设计
我们已经对基于RAW API的TCP应用有了了解。我们在实现TCP服务器的实验时就提到过对于更复杂的应用和应用层协议只是在功能上的差别,从实现的结构及流程来说是完全一致的。所以对于实现HTTP服务器需要使用到的函数及整个操作流程我们就不再叙述了。重点说一说不同的地方。
首先HTTP服务器是基于TCP的,所以其我们先将其当作TCP服务器来实现。需要注意的是,HTTP协议有其专门的操作端口:80。所以我们设计服务器时需要使用这个端口。
在这里,我们设计一个简单的HTTP服务器,当客户端连接到服务器之后,如果收到的是html请求,则返回一个我们预先设定好的网页。正常返回这个网页,HTTP的功能就完成了,HTTP服务器会主动断开与客户端的连接。
3、 TTP服务器实现
既然是基于TCP的HTTP服务器,我们佷显然依然按照TCP服务器的结构来实现。我们依然将其划分为三个部分来实现。首先要实现的是HTTP服务器的初始化。
/* HTTP服务器初始化配置*/
void Http_Server_Initialization(void)
{
struct tcp_pcb *pcb = NULL; /* 生成一个新的TCP控制块 */
pcb = tcp_new(); /* 控制块绑定到本地IP和对应端口 */
tcp_bind(pcb, IP_ADDR_ANY, TCP_HTTP_SERVER_PORT); /* 服务器进入侦听状态 */
pcb = tcp_listen(pcb); /* 注册服务器accept回调函数 */
tcp_accept(pcb, HttpServerAccept); }
从上面的代码不难看出,与TCP服务器的初始化一样:建立控制块,为控制块绑定本地IP和端口,服务器监听控制块同时注册接收处理回调函数。所以接下来就是实现接收处理回调函数。
/* HTTP接收回调函数,客户端建立连接后,本函数被调用 */
static err_t HttpServerAccept(void *arg, struct tcp_pcb *pcb, err_t err)
{
/*注册HTTP服务器回调函数*/
tcp_recv(pcb, HttpServerCallback); return ERR_OK;
}
客户端连接成功后就会调用接收处理回调函数。该函数为tcp_accept_fn类型,注册到了监听控制块的accept字段。在这个函数中,我们需要注册HTTP服务器处理函数。其功能就由这个函数决定。
/* HTTP服务器信息处理回调函数 */
static err_t HttpServerCallback(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
char *data = NULL; if (p != NULL)
{
/* 更新接收窗口 */
tcp_recved(pcb, p->tot_len);
data = p->payload; /* 如果是http请求,返回html信息,否则无响应 */
if(p->len >= && data[] == 'G'&& data[] == 'E'&& data[] == 'T')
{
tcp_write(pcb, htmlMessage, sizeof(htmlMessage), );
}
else
{ }
pbuf_free(p);
tcp_close(pcb);
}
else if (err == ERR_OK)
{
return tcp_close(pcb);
}
return ERR_OK;
}
这个HTTP服务器非常简单,我们只是实现了GET方法。也就是说,收到客户端的html请求后,我们检测其要求,如果是GET方法,我们就返回预先设定好的网页,否则无返回。然后关闭这一连接。如果我们想要实现更复杂的功能,或者需要支持HTTP协议的其他方法,只需要扩展这个函数就可以了。
4、 结论
HTTP协议是一种使用非常广泛的协议,其基于TCP基础上运行,所以在我们前面已经实现TCP服务器及客户端的情况下,开发HTTP服务器应用就显得简单了。在这一篇我们基于LwIP实现了一个简单的HTTP服务器应用,我们并对其进行了简单的测试,虽然我们只是实现了GET方法,但经测试设计是正确的。如果需要设计其他方法的HTTP应用只需在此基础上添加即可。
欢迎关注:
LwIP应用开发笔记之七:LwIP无操作系统HTTP服务器的更多相关文章
- LwIP应用开发笔记之一:LwIP无操作系统基本移植
现在,TCP/IP协议的应用无处不在.随着物联网的火爆,嵌入式领域使用TCP/IP协议进行通讯也越来越广泛.在我们的相关产品中,也都有应用,所以我们结合应用实际对相关应用作相应的总结. 1.技术准备 ...
- LwIP应用开发笔记之四:LwIP无操作系统TFTP服务器
前面我们已经实现了UDP的回环客户端和回环服务器的简单应用,接下来我们实现一个基于UDP的简单文件传输协议TFTP. 1.TFTP协议简介 TFTP是TCP/IP协议族中的一个用来在客户机与服务器之间 ...
- LwIP应用开发笔记之六:LwIP无操作系统TCP客户端
上一篇我们基于LwIP协议栈的RAW API实现了一个TCP服务器的简单应用,接下来一节我们来实现一个TCP客户端的简单应用. 1.TCP简述 TCP(Transmission Control Pro ...
- LwIP应用开发笔记之五:LwIP无操作系统TCP服务器
前面我们实现了UDP服务器及客户端以及基于其上的TFTP应用服务器.接下来我们将实现同样广泛应用的TCP协议各类应用. 1.TCP简述 TCP(Transmission Control Protoco ...
- LwIP应用开发笔记之八:LwIP无操作系统HTTP客户端
前面我们实现了TCP服务器和客户端的简单应用,接下来我们实现一个基于TCP协议的应用协议,那就是HTTP超文本传输协议 1.HTTP协议简介 超文本传输协议(Hyper Text Transfer P ...
- LwIP应用开发笔记之二:LwIP无操作系统UDP服务器
前面我们已经完成了LwIP协议栈基于逻辑的基本移植,在这一节我们将以RAW API来实现UDP服务器. 1.UDP协议简述 UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包, ...
- LwIP应用开发笔记之三:LwIP无操作系统UDP客户端
前一节我们实现了基于RAW API的UDP服务器,在接下来,我们进一步利用RAW API实现UDP客户端. 1.UDP协议简述 UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包 ...
- Modbus库开发笔记之七:Modbus其他辅助功能开发
前面开发了各种应用,但是却一直没有提到一个问题,你就是对具体的数据进行读写操作.对于Modbus来说标准的数据有4种:线圈数据(地址:0000x).输入状态量数据(地址:1000x).保持寄存器数据( ...
- PID控制器开发笔记之七:微分先行PID控制器的实现
前面已经实现了各种的PID算法,然而在某些给定值频繁且大幅变化的场合,微分项常常会引起系统的振荡.为了适应这种给定值频繁变化的场合,人们设计了微分先行算法. 1.微分先行算法的思想 微分先行PID控制 ...
随机推荐
- Show which git tag you are on?
git查看当前代码是在那个tag? reference: https://stackoverflow.com/questions/3404936/show-which-git-tag-you-are- ...
- Feign 报错:The bean 'service-producer.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
报错: 2019-09-17 20:34:47.635 ERROR 59509 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : ******* ...
- 26、pathlib文件系统模块(了解)
一.pathlib库官方定义 pathlib 是Python内置库,Python 文档给它的定义是 Object-oriented filesystem paths(面向对象的文件系统路径).path ...
- post Cache
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5 POST The POST method is used to request ...
- What Is React?--MVC
React is a declarative, efficient, and flexible JavaScript library for building user interfaces. It ...
- Generative Adversarial Networks overview(2)
Libo1575899134@outlook.com Libo (原创文章,转发请注明作者) 本文章会先从Gan的简单应用示例讲起,从三个方面问题以及解决思路覆盖25篇GAN论文,第二个大部分会进一步 ...
- Openwrt build env setup(9)
reference : https://openwrt.org/docs/guide-developer/quickstart-build-images Install dependence pack ...
- 洛谷P2038 无线网络发射器选址
题目描述 随着智能手机的日益普及,人们对无线网的需求日益增大.某城市决定对城市内的公共场所覆盖无线网. 假设该城市的布局为由严格平行的 \(129\) 条东西向街道和 \(129\) 条南北向街道所形 ...
- minimap2 长reads比对工具
minimap2 github 官网 https://github.com/lh3/minimap2 安装 git clone https://github.com/lh3/minimap2 cd m ...
- FileInputFormat 的实现之TextInputFormat
说明 TextInputFormat默认是按行切分记录record,本篇在于理解,对于同一条记录record,如果被切分在不同的split时是怎么处理的.首先getSplits是在逻辑上划分,并没有物 ...