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 >=3 && data[0] == 'G'&& data[1] == 'E'&& data[2] == 'T'){tcp_write(pcb, htmlMessage, sizeof(htmlMessage), 1);}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应用只需在此基础上添加即可。

欢迎关注:

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

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

相关文章

LwIP应用开发笔记之八:LwIP无操作系统HTTP客户端

前面我们实现了TCP服务器和客户端的简单应用,接下来我们实现一个基于TCP协议的应用协议,那就是HTTP超文本传输协议 1、HTTP协议简介 超文本传输协议(Hyper Text Transfer Protocol),简称HTTP,是一种基于T…

LwIP应用开发笔记之九:LwIP无操作系统TELNET服务器

前面我们已经实现了基于RAW API的TCP服务器和客户端,也在此基础上实现了HTTP应用。接下来我们实现一个基于TCP的Telnet服务器应用。 1、Telnet协议简介 Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了…

在ARM Cortex-M上实现FreeRTOS性能计数器

说明:本文翻译自Erich Styger的文章《Implementing FreeRTOS Performance Counters on ARM Cortex-M》,文章的权属属于原作者。 当使用像FreeRTOS这样的RTOS时,迟早要问一个问题:每个任务花费多少时间?基于Eclipse的M…

STM32学习及开发笔记八:采用主从计时器实现精确脉冲输出

脉冲信号用于设备控制是非常常见的,但在一些情况下,我们希望精确的控制脉冲的数量以实现对运动的精确控制。实现的方式也许有多种多样,但使用计时器来实现此类操作是人们比较容易想到的。 1、原理概述 我们知道在STM32平台上,使…

外设驱动库开发笔记0:EPD总体设计

在产品开发过程中,不可避免需要使用很多外部的元件及传感器,这些元器件也许是板载的,也许是板外的,但不管怎样,为其开发驱动程序都是必须的。每次都需要为这些元器件编写驱动程序。但每次重复编写调试很麻烦&#xff0…

外设驱动库开发笔记1:AD56xx系列DAC驱动

DAC在我们的项目中经常使用到,而使用最多的就是AD56xx系列,包括有单通道的AD5662、双通道的AD5623和AD5663、以及四通道的AD5624和AD5664等。出于方便复用的原因,我们设计并实现AD56xx系列DAC的驱动。 1、功能概述 AD56xx系列DAC属于nanoDA…

外设驱动库开发笔记2:AD8400系列数字电位器驱动

一些时候我们需要在系统使用过程中改变某些电路电阻值以达到改变设定的目的,这时候我们就会使用电位器。在我们使用数字控制电路时多选择数字电位器。在这一篇我们就来设计AD8400系列数字电位器的驱动。 1、功能概述 AD8400/AD8402/AD8403分别是单通道/双通道/四通…

外设驱动库开发笔记3:AD527x系列数字电位器驱动

在一些时候我们需要使用精度更高的数字电位器来实现我们的应用。我们经常使用AD527x系列数字电位器来实现这类应用。在通常情况下,AD527x系列数字电位器完全能够满足要求。为了减少重复工作,在这里我们将分系并实现AD527x系列数字电位器的驱动。 1、功能…

PID控制器改进笔记之一:改进PID控制器之参数动态调整

前面我们发布了一系列PID控制器相关的文章,包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能,也在实际使用中取得了良好效果,但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

外设驱动库开发笔记4:AD9833函数发生器驱动

很多时候我们需要输出某种函数信号,如方波、三角波、正弦波等,但想要获得这样的函数信号,不论是硬件电路还是软件实现,却并不是一件简单的事情。不过AD9833这类函数生成芯片可以简化这方面的操作,这一节我们就来设计并…

PID控制器改进笔记之二:改进PID控制器之手自动切换

前面我们发布了一系列PID控制器相关的文章,包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能,也在实际使用中取得了良好效果,但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

外设驱动库开发笔记5:AD7705系列ADC驱动

我们的经常需要采集一些精度要求较高的模拟信号,使用MCU集成的ADC难以达到要求、所以我们需要独立的ADC芯片。这一节我们就来设计并实现AD7705芯片的驱动、并探讨驱动的使用方法。 1、功能概述 AD7705/AD7706是用于低频测量的完整模拟前端。可以直接从传感器接收低…

PID控制器改进笔记之三:改进PID控制器之正反作用

前面我们发布了一系列PID控制器相关的文章,包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能,也在实际使用中取得了良好效果,但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

PID控制器改进笔记之四:改进PID控制器之设定值响应

前面我们发布了一系列PID控制器相关的文章,包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能,也在实际使用中取得了良好效果,但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

PID控制器改进笔记之五:改进PID控制器之串级设定

前面我们发布了一系列PID控制器相关的文章,包括经典PID控制器以及参数自适应的PID控制器。这一系列PID控制器虽说实现了主要功能,也在实际使用中取得了良好效果,但还有很多的细节部分可以改进以提高性能和灵活性。所以在这篇中我们来讨论改进…

滤波器开发之一:基于算数平均的平滑滤波器

信号采集是非常常见的需求,我们也总是希望采集到的数据是纯净而真实的,但这只是我们的希望。环境中存在太多的干扰信号,为了让我们得到的数据尽可能地接近实际值,我们需要降低这些干扰信号的影响,于是就有了滤波器的用…

外设驱动库开发笔记6:AD719x系列ADC驱动

前面我们讨论了AD7705这种ADC器件的驱动开发,在实际中我们使用更多的是AD719x系列的ADC芯片、包括有AD7191、AD7192和AD7193等。接下来我们就来设计并开发AD719x的驱动程序。 1、功能概述 AD7192是一款适合高精密测量应用的低噪声完整模拟前端,内置一个…

滤波器开发之二:基于算数平均的带阻平滑滤波器

信号采集是非常常见的需求,我们也总是希望采集到的数据是纯净而真实的,但这只是我们的希望。环境中存在太多的干扰信号,为了让我们得到的数据尽可能地接近实际值,我们需要降低这些干扰信号的影响,于是就有了滤波器的用…

滤波器开发之三:基于算数平均的阶进平滑滤波器

信号采集是非常常见的需求,我们也总是希望采集到的数据是纯净而真实的,但这只是我们的希望。环境中存在太多的干扰信号,为了让我们得到的数据尽可能地接近实际值,我们需要降低这些干扰信号的影响,于是就有了滤波器的用…

外设驱动库开发笔记7:LTC2400系列ADC驱动

有些时候我们需要对高精度的ADC来处理一些要求较高的模拟量采集。在处理温控器的过程中我们就使用到了LTC2400这款ADC。接下来我们就来设计并实现LTC2400的驱动。 1、功能概述 LTC2400是一个供电电压2.7V到5.5V的微功率24位转换器,集成了振荡器、4ppm INL和0.3ppm…