开发板功能区分布图
开发板俯视图
2、HTTP协议介绍 HTTP协议简介 HTTP(HyperText Transfer Protocol)协议,即超文本传输协议,是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP 协议是基于 TCP/IP 协议的网络应用层协议。
HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)。服务器接收到请求之后,通过接收到的信息判断响应方式,并且给予客户端相应的响应,完成整个 HTTP 数据交互流程。
HTTP 请求/响应的步骤 | |
---|---|
1. 客户端连接到Web服务器 | 一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。 |
2. 发送HTTP请求 | 通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和数据包4部分组成。 |
3. 服务器接受请求并返回HTTP响应 | Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。 |
4. 释放连接TCP连接 | 若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求; |
5. 客户端浏览器解析HTML内容 | 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。 |
客户端发送一个HTTP请求到服务器的请求头主要包括:请求行、请求头部、空行、数据包
如下图是一个 POST 请求的信息:
状态代码 | 类别 | 原因短语 |
---|---|---|
1xx | Infomational(信息性状态码) | 接收的请求正在处理 |
2xx | Success(成功状态码) | 请求正常处理完毕 |
3xx | Redirection(重定向状态码) | 需要进行附加 *** 作以完成请求 |
4xx | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5xx | Server Error(服务器错误状态码) | 服务器处理请求出错 |
WebClient客户端代码 | |
---|---|
web_strdup | 将字符串复制到新开辟的内存空间 |
webclient_session_create | 创建webclient客户端 |
webclient_header_fields_add | 将请求句柄封装到客户端缓存区 |
webclient_header_fields_get | 解析响应数据的单一消息报头 |
webclient_header_length_response | 获取请求头的长度 |
webclient_handle_response | 获取服务器响应的状态码 |
webclient_data_analysis | 获取服务器返回的数据包 |
HTTP请求方法 | |
---|---|
webclient_get_method | 客户端GET请求方法 |
webclient_post_method | 客户端POST请求方法 |
修改ESP8266.c代码中的NET_DEVICE_LinkServer_Init函数(代码在上一章)
ESP8266_RETTYPE NET_DEVICE_LinkServer_Init(void)
{
unsigned char errCount = 0, errType = 0;
char cfgBuffer[70];
switch(netDeviceInfo.initStep)
{
case 0:
if(ESP8266_Net_Mode_Choose(STA) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
case 1:
if(ESP8266_Enable_MultipleId(DISABLE) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
case 2:
if(ESP8266_JoinAP(netDeviceInfo.staName,netDeviceInfo.staPass) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
case 3:
//注释掉这一行,因为请求的网址不同
// if(ESP8266_Link_Server(enumTCP,netDeviceInfo.staIPAddress,netDeviceInfo.staPort,Single_ID_0) == ESP8266_OK)
netDeviceInfo.initStep++;
break;
default:
netDeviceInfo.netWork = 1;
errType = 3;
break;
}
return errType;
}
在webclient.h中编写以下代码
#ifndef __WEBCLIENT_H_
#define __WEBCLIENT_H_
#include "sys.h"
#ifndef WEBCLIENT_OK
#define WEBCLIENT_OK 0
#endif
#ifndef WEBCLIENT_NOK
#define WEBCLIENT_NOK 1
#endif
typedef struct __webclient_header
{
char* buffer;
unsigned int length; /* content header buffer size */
unsigned int size; /* maximum support header size */
}webclient_header;
typedef struct __webclient_session
{
webclient_header* header; /* webclient response header information */
int resp_status;
int content_length;
}webclient_session;
void webclient_get_method(void);
void webclient_post_method(void);
#endif
在webclient.c中编写以下代码
#include "webclient.h"
#include "ESP8266.h"
#include "usart.h"
#include "StringUtil.h"
//将字符串复制到新开辟的内存空间
char* web_strdup(const char* s)
{
uint16_t len = strlen(s) + 1;
char* tmp = (char*)malloc(len);
if (!tmp)
return NULL;
memcpy(tmp, s, len);
return tmp;
}
//创建webclient客户端
webclient_session* webclient_session_create(uint16_t header_sz)
{
webclient_session* session;
/* create session */
session = (webclient_session*)calloc(1, sizeof(webclient_session));
if (session == NULL)
{
printf("webclient create failed, no memory for webclient session!");
return NULL;
}
/* initialize the socket of session */
session->content_length = -1;
session->header = (webclient_header*)calloc(1, sizeof(webclient_header));
if (session->header == NULL)
{
printf("webclient create failed, no memory for session header buffer!");
free(session->header);
free(session);
session = NULL;
return NULL;
}
session->header->size = header_sz;
session->header->buffer = (char*)calloc(1, header_sz);
if (session->header->buffer == NULL)
{
printf("webclient create failed, no memory for session header buffer!");
free(session->header);
free(session);
session = NULL;
return NULL;
}
return session;
}
//将请求句柄封装到客户端缓存区
unsigned char webclient_header_fields_add(webclient_session* session, const char* fmt, ...)
{
int length;
va_list args;
va_start(args, fmt);
length = vsnprintf(session->header->buffer + session->header->length, session->header->size - session->header->length, fmt, args);
if (length < 0)
{
printf("add fields header data failed, return length(%d) error.", length);
return WEBCLIENT_NOK;
}
va_end(args);
session->header->length += length;
if (session->header->length >= session->header->size)
{
printf("not enough header buffer size(%d)!", session->header->size);
return WEBCLIENT_NOK;
}
return WEBCLIENT_OK;
}
//解析响应数据的单一消息报头
const char* webclient_header_fields_get(webclient_session* session, const char* fields)
{
char* resp_buf = NULL;
size_t resp_buf_len = 0;
char* dataPtr;
char* mime_ptr = NULL;
resp_buf = session->header->buffer;
dataPtr = strstr(resp_buf,fields);
if(dataPtr != NULL)
{
mime_ptr = strstr(dataPtr,":");
if(mime_ptr != NULL)
{
mime_ptr += 1;
while (*mime_ptr && (*mime_ptr == ' ' || *mime_ptr == '\t'))
mime_ptr++;
return mime_ptr;
}
}
return NULL;
}
//获取请求头的长度
unsigned int webclient_header_length_response(webclient_session* session)
{
return (strlen(session->header->buffer) - session->content_length - 4);
}
//获取服务器响应的状态码
unsigned char webclient_handle_response(webclient_session* session)
{
int rc = 0;
char* mime_buffer = NULL;
char* mime_ptr = NULL;
const char* transfer_encoding;
int i;
if(webclient_header_fields_get(session, "Content-Length") != NULL)
{
session->content_length = atoi(webclient_header_fields_get(session, "Content-Length"));
}
session->header->length = webclient_header_length_response(session);
/* get HTTP status code */
mime_ptr = web_strdup(session->header->buffer);
if (strstr(mime_ptr, "HTTP/1."))
{
char* ptr = mime_ptr;
ptr += strlen("HTTP/1.x");
printf("ptr: %s\r\n", ptr);
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
ptr++;
/* Terminate string after status code */
for (i = 0; ((ptr[i] != ' ') && (ptr[i] != '\t')); i++);
ptr[i] = ';'=
session->resp_status ( int)strtol(,ptrNULL ,10 );}
if
( )mime_ptrfree
{
()mime_ptr;}
return
; session->resp_status}
//获取服务器返回的数据包
uint8_t
*webclient_data_analysis (*webclient_session) sessionchar
{
*; dataptrchar
*= mime_ptr ; session->header->buffer=
//printf("session->header->buffer:%s\r\n",session->header->buffer);
dataptr strstr (,mime_ptr"\r\n\r\n");if
(!=dataptr NULL )+=
{
dataptr 4 ;return
( uint8_t*);dataptr}
return
NULL ;}
//客户端GET请求方法
void
webclient_get_method (void)*
{
webclient_session; sessionuint8_t
= uwRet ; WEBCLIENT_NOKuint8_t
* ;dataPtr=
session webclient_session_create ()RX_BUF_MAX_LEN;if
(==session NULL )printf
{
("创建客户端失败\r\n");goto
; __exit}
// webclient_header_fields_add(session,"GET http://%s:%s/getBinFile?IMEI=868626044941824 HTTP/1.1\r\n",netDeviceInfo.staIPAddress,netDeviceInfo.staPort);
// webclient_header_fields_add(session,"\r\n");
// GET https://api.seniverse.com/v3/weather/now.json?key=smtq3n0ixdggurox&location=nanning&language=zh-Hans&unit=c HTTP/1.1\r\n
webclient_header_fields_add
(,session"GET https://api.seniverse.com/v3/weather/now.json?key=smtq3n0ixdggurox&location=nanning&language=en&unit=c HTTP/1.1\r\n");webclient_header_fields_add
(,session"Host:www.baidu.com\r\n");webclient_header_fields_add
(,session"\r\n");if
(ESP8266_DisconnectServer(0)!= ) ESP8266_OK//断开服务器连接, goto
; __exitif
(ESP8266_Link_Server(,enumTCP"api.seniverse.com","80",)Single_ID_0== ) ESP8266_OK//连接服务器 =
{
uwRet ESP8266_SendData (,DISABLE(uint8_t*),session->header->buffer,session->header->length)Single_ID_0;//发送数据 if
(==uwRet ) WEBCLIENT_OK//发送成功 =
{
dataPtr ESP8266_GetIPD (,DISABLE2000);//解析服务器返回的数据 if
(!=dataPtr NULL )memset
{
(,session->header->buffer0,)session->header->size;=
session->header->length 0 ;memcpy
(,session->header->buffer,dataPtr)session->header->size;if
(webclient_handle_response()session== 200 )//解析服务器返回的状态码 printf
{
(,"strlen(session->header->buffer):%d\r\n"strlen()session->header->buffer);printf
(,"session->header->length:%d\r\n")session->header->length;=
dataPtr webclient_data_analysis ()session;//获取服务器返回的数据 if
(!=dataPtr NULL )if
{
(strstr((char*),dataPtr"+IPD,"))//查找是否有IPD头 =
{
dataPtr Filter_string ((char*),dataPtr(char*)"+IPD,",(char*)":");//过滤IPD头 if
(!=dataPtrNULL)printf
{
("dataPtr:%s\r\n",)dataPtr;}
//printf("session->content_length:%d\r\n",session->content_length);
}
else
printf
{
("dataPtr:%s\r\n",)dataPtr;}
}
}
}
}
}
:
__exitif
(!=session->header->buffer NULL )free
{
()session->header->buffer;=
session->header->bufferNULL;}
if
(!=session NULL )free
{
()session;=
session NULL ;}
}
//客户端POST请求方法
void
webclient_post_method (void)*
{
webclient_session; sessionuint8_t
= uwRet ; WEBCLIENT_NOKuint8_t
* ;dataPtr=
session webclient_session_create ()RX_BUF_MAX_LEN;if
(==session NULL )printf
{
("创建客户端失败\r\n");goto
; __exit}
// webclient_header_fields_add(session,"GET http://%s:%s/getBinFile?IMEI=868626044941824 HTTP/1.1\r\n",netDeviceInfo.staIPAddress,netDeviceInfo.staPort);
// webclient_header_fields_add(session,"\r\n");
// GET https://api.seniverse.com/v3/weather/now.json?key=smtq3n0ixdggurox&location=nanning&language=zh-Hans&unit=c HTTP/1.1\r\n
webclient_header_fields_add
(,session"POST /devices/583402349/datapoints HTTP/1.1\r\n");webclient_header_fields_add
(,session"api-key:rBIh6FFxeyW=kVJyybB2FzD5QAQ=\r\n");webclient_header_fields_add
(,session"Host: api.heclouds.com\r\n");webclient_header_fields_add
(,session"Content-Length:66\r\n");webclient_header_fields_add
(,session"\r\n");webclient_header_fields_add
(,session"{\"datastreams\":[{\"id\":\"test_stream\",\"datapoints\":[{\"value\":30}]}]}");if
(ESP8266_DisconnectServer(0)!= ) ESP8266_OK//断开服务器连接 goto
; __exitif
(ESP8266_Link_Server(,enumTCP"api.heclouds.com","80",)Single_ID_0== ) ESP8266_OK//连接服务器 =
{
uwRet ESP8266_SendData (,DISABLE(uint8_t*),session->header->buffer,session->header->length)Single_ID_0;//发送数据 if
(==uwRet ) WEBCLIENT_OK//发送成功 =
{
dataPtr ESP8266_GetIPD (,DISABLE2000);//解析服务器返回的数据 if
(!=dataPtr NULL )memset
{
(,session->header->buffer0,)session->header->size;=
session->header->length 0 ;memcpy
(,session->header->buffer,dataPtr)session->header->size;if
(webclient_handle_response()session== 200 )//解析服务器返回的状态码 printf
{
(,"strlen(session->header->buffer):%d\r\n"strlen()session->header->buffer);printf
(,"session->header->length:%d\r\n")session->header->length;=
dataPtr webclient_data_analysis ()session;//获取服务器返回的数据 if
(!=dataPtr NULL )if
{
(strstr((char*),dataPtr"+IPD,"))//查找是否有IPD头 =
{
dataPtr Filter_string ((char*),dataPtr(char*)"+IPD,",(char*)":");//过滤IPD头 if
(!=dataPtrNULL)printf
{
("dataPtr:%s\r\n",)dataPtr;}
//printf("session->content_length:%d\r\n",session->content_length);
}
else
printf
{
("dataPtr:%s\r\n",)dataPtr;}
}
}
}
}
}
:
__exitif
(!=session->header->buffer NULL )free
{
()session->header->buffer;=
session->header->bufferNULL;}
if
(!=session NULL )free
{
()session;=
session NULL ;}
}
#
在StringUtil.h中编写以下代码
ifndef__STRING_UTIL_h #
define__STRING_UTIL_h #
include"string.h" #
include#
include#
include"usart.h" int
find_end (char* , usart_bufferint ) number;int
Find_string (char* ,pcBufchar* ,leftchar* ,rightchar * )pcRes;void
smart_array (unsignedchar *, addrunsignedchar * )ip;void
Hex2Str (char* ,pbDestchar * ,pbSrcint ) nLen;unsigned
char *Filter_string (char*, pcBufchar *, leftchar *) right;#
endif#
在StringUtil.c中编写以下代码
include"StringUtil.h" /**
*@brief ip网络地址转换
*@param adr:地址 ip:ip
*@return 无
*/
void
smart_array (unsignedchar *, addrunsignedchar * )ipint
{
; ichar
[ taddr30];char
* ; nexttokchar
; numstrcpy
(,taddr(char* ))addr;=
nexttok ; taddrfor
(=i 0 ;< i 4 ; ++ i)=
{
nexttok strtok (,nexttok".");// if(nexttok[0] == '0' && nexttok[1] == 'x') num = atoi16(nexttok+2,0x10);
// else num = atoi16(nexttok,10);
[
ip]i= ; num=
nexttok NULL ;}
}
/***********************************************************
函数名称:Find_string(char *pcBuf,char*left,char*right, char *pcRes)
函数功能:寻找特定字符串
入口参数:
char *pcBuf 为传入的字符串
char*left 为搜索字符的左边标识符 例如:"["
char*right 为搜索字符的右边标识符 例如:"]"
char *pcRes 为输出转存的字符串数组
返回值:用来校验是否成功,无所谓的。
备注: left字符需要唯一,right字符从left后面开始唯一即可
服务器下发命令举例:+MQTTPUBLISH: 0,0,0,0,/device/NB/zx99999999999999_back,6,[reastrobot]
此函数会 *** 作内存空间 强烈建议 提前清空buf memset(Find_token,0x00,sizeof(Find_token));
***********************************************************/
int
Find_string (char* ,pcBufchar* ,leftchar* ,rightchar * )pcReschar
{
* =pcBegin NULL ;char
* =pcEnd NULL ;=
pcBegin strstr (,pcBuf) left;//找到第一次出现的位置 =
pcEnd strstr (+pcBeginstrlen()left,) right;//找到右边标识第一次出现位置 if
(==pcBegin NULL || == pcEnd NULL || ) pcBegin > pcEndprintf
{
("string name not found!\n");return
0 ;}
else
+=
{
pcBegin strlen ()left;memcpy
(,pcRes, pcBegin- pcEnd)pcBegin;return
1 ;}
}
//+IPD, 268:hello world\r\n
//过滤left和right之间的字符串,返回过滤之后的字符串
unsigned
char *Filter_string (char*, pcBufchar *, leftchar *) rightchar
{
*; ptrIPD=
ptrIPD strstr ((char*),pcBuf) left;//搜索“left”头 if
( ==ptrIPD NULL )// UsartPrintf(USART_DEBUG, "\"left\" not found\r\n");
{
}
else
=
{
ptrIPD strstr (,ptrIPD) right;//找到'right' if
( !=ptrIPD NULL )+=
{
ptrIPDstrlen()right;return
( unsignedchar *)()ptrIPD;}
else
return
NULL ;}
}
//int Smart_array(char *pcBuf,char *fu)
//memcpy(&citc_server_ip[0],back_ip,strstr(back_ip,".")-back_ip);
//{
// char *pcBegin = NULL;
// int8_t len =0;
// pcBegin = strstr(pcBuf, fu);//找到第一次出现的位置
// memcpy(&pcRes[i], pcBuf,pcBegin-pcBuf);
// }
// len= strlen(pcBuf);
// pcBegin = strstr(pcBuf, fu);//找到第一次出现的位置
// memcpy(&pcRes[0], pcBuf,pcBegin-pcBuf);
//}
//寻找字符后面最近的结束符
// int i;
//int find_end(char * usart_buffer, int number) {
// return number + i+2 ; //如果有换行符 需要加4
// for (i = 0; i < 100; i++) {
// if ((usart_buffer[number + i] == '/') && (usart_buffer[number + i + 1] == '>')) {
// }
// }
//}
//智能查找和匹配字符串
int8_t
Find_AttributeStringAll (char* ,pcBufchar * ,pcRestuint16_t, rowuint8_t, colchar * ,leftchar * ,rightuint8_t* )Numchar
{
[ pcFind20]= 0 {};char
* =pcBegin NULL ;char
* =pcEnd NULL ;=
pcEnd ; pcBufwhile
(1)memset
{
(,pcFind0,20);=
pcBegin strstr (+pcEnd1,) left;if
((==pcBegin NULL )|| ( strcmp(,pcBegin"}")== 0 ))printf
{
("找到指定字符 !\n");return
1 ;}
else
=
{
pcEnd strstr (+pcBeginstrlen()left,) right;if
( (==pcEnd NULL )|| ( )pcBegin > pcEnd)printf
{
("Mail name not found!\n");return
- 1;}
else
if
{
(*)Num>rowreturn
{
1 ;}
else
+=
{
pcBegin strlen ()left;memcpy
(,pcFind, pcBegin- pcEnd ) pcBegin;memset
(+pcRest**Num,col0,)col;memcpy
(+pcRest**Num,col,pcFindsizeof()pcFind);(
*)Num++ ;}
}
}
}
}
void
Hex2Str (char* ,pbDestchar * ,pbSrcint ) nLenchar
{
, ddl;ddhint
; ifor
( =i0;< i;nLen++ i)=
{
ddh 48 + [ pbSrc]i/ 16 ;=
ddl 48 + [ pbSrc]i% 16 ;if
( 57ddh > )= ddh + ddh 7 ;if
( 57ddl > )= ddl + ddl 7 ;[
pbDest*i2]= ; ddh[
pbDest*i2+1]= ; ddl}
[
pbDest*nLen2]= ';' }void
Str2Hex
( char*,char str* )const hexchar
{
* ="0123456789ABCDEF" cHex ; int=
0 i;for(
int=0 j ;<strlen j ( );str++) junsignedint
{
= ( a unsigned int) [] str;j[++
hex]i=[ ( cHex&0xf0a ) 4] >> ;[++
hex]i=[ ( cHex&0x0fa ) ];}[
]
hex=i';' } /* USER CODE BEGIN 0 */#
define
在main.c中编写以下代码
REQUEST_METHOD
0//0:GET请求,1:POST请求 /* USER CODE END 0 */ int main
(
void )/* USER CODE BEGIN 1 */unsignedchar
{
*
= NULL; dataPtr uint32_t =0
; request_time uint32_t =0
; netErr_time = ;uint32_t
ESP8266_RETTYPE uwRet = ESP8266_NOK0
; total_len/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init
(
)
;/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */
SystemClock_Config
(
)
;/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */
MX_GPIO_Init
(
)
;MX_DMA_Init()
;MX_LPUART1_UART_Init()
;MX_USART1_UART_Init()
;MX_TIM2_Init()
;/* USER CODE BEGIN 2 */TIM_Interupt_Enable(
)
;//使能串口中断USART_Interupt_Enable( )
;//使能定时器中断/* USER CODE END 2 *//* Infinite loop */ /* USER CODE BEGIN WHILE */
while
(
1
) /* USER CODE END WHILE *//* USER CODE BEGIN 3 */if
{
(
!
.)//如果网络未连接netDeviceInfoifnetWork( NET_DEVICE_Init
{
()==)printf ( ESP8266_OK"初始化成功\r\n"
{
);}}if
(
-
10000)time2Count //(1ms * 2000)相当于延时2秒钟 request_time >= if( .
{
)//如果网络连接成功netDeviceInfo#netWorkifREQUEST_METHOD
{
webclient_get_method( )
;#elsewebclient_post_method
()
;#endif}
}}
/* USER CODE END 3 */
}
实现的功能
1、上电自动连接WIFI
2、如果是POST请求,则请求POST接口(我这里用的是ONENET的POST接口)
4、实验现象
3、如果是GET请求,则请求GET接口(我这里用的是心知天气的GET接口) |
POST请求(Onenet物联网平台)
GET请求(心知天气)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)