单片机使用HTTP POST方式发送数据
/报文格式 flag=1&ver=1.00&type=RealData&SERIAL=1&ST=1510260128&UT=2018-02-04 15:24:32&data={"ST":"1510260128","TT":"2018-02-04 18:00:00","Z":1.234,"VT":12.56,"ZT":128}* 参数:pHandle:句柄;* 参数:pHandle:句柄;//POS
HTTP请求是依赖TCP的,也就是在单片机上面,我们一样可以使用,无非就是先发送一个http请求头,再发送正文,比如我最近就使用了http post方式发送数据到服务器,服务器端使用的是WEB API,单片机使用的STM32 与SIM800C,SIM800C使用GPRS连接服务器,采用透传方式,TCP连接,在这里就不讲述TCP连接方式了,假设你已经会使用TCP方式连接服务器,并发送数了。
以下代码只会教会你怎么发起http请求,具体的发送接口底层这里不做说明,以及json打包等操作也不做说明,json打包就是不停的使用sprintf即可。
-
#define POST_VER "1.00" //此处必须是浮点或整数
-
#define POST_REAL_DATA_STRING "RealData" //实时数据上报定义
-
#define POST_API_URL "/api/RTU_DataInterface" //接口地址
-
-
//POST请求的http头信息,参数1:API地址,参数2:服务器IP,参数3:后续数据长度
-
static
const
char *
const HTTP_POST_HEAD =
-
{
-
"POST %s HTTP/1.1\r\n\
-
Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n\
-
X-Requested-With: XMLHttpRequest\r\n\
-
Host: %s\r\n\
-
Content-Length: %d\r\n\
-
Expect: 100-continue\r\n\
-
Connection: Keep-Alive\r\n"
//最后面必须空一行
-
}
//发送http post请求
-
/*************************************************************************************************************************
-
* 函数 : bool POST_SendHttpHead(POST_HANDLE *pHandle, u16 DataLen)
-
* 功能 : 发送http POST请求头
-
* 参数 : pHandle:句柄;AcqTime:观测时间;pData:实时数据指针;SerialNumber:流水号;AlarmStatus:报警定义
-
* 返回 : 长度
-
* 依赖 : 无
-
* 作者 : cp1300@139.com
-
* 时间 : 2018-02-04
-
* 最后修改时间 : 2018-02-04
-
* 说明 : 将报文打包写入到了pPackDataBuff中
-
*************************************************************************************************************************/
-
bool POST_SendHttpHead(POST_HANDLE *pHandle, u16 DataLen)
-
{
-
int len;
-
char IpBuff[
16];
-
-
if(pHandle->pHttpHeadDataBuff ==
NULL)
DEBUG(
"pHttpHeadDataBuff未初始化\r\n");
-
-
HTTP_POST_GetHost(IpBuff, pHandle->SendDataTelAttr.CentralIndex);
//获取服务器ip
-
len =
sprintf((
char *)pHandle->pHttpHeadDataBuff, HTTP_POST_HEAD, POST_API_URL, IpBuff, DataLen);
//http请求头打包
-
-
uart_printf(
"http头(%dB):%s\r\n",len, (
char*)pHandle->pHttpHeadDataBuff);
-
return pHandle->
pSendData(pHandle->pHttpHeadDataBuff, len);
-
}
-
//获取指定服务器的IP地址
-
u8 HTTP_POST_GetHost(char *pIpBuff, u8 ServerIndex)
-
{
-
u16 ip[
4];
-
-
if(ServerIndex >
3)
-
{
-
return
sprintf(pIpBuff,
"localhost");
-
}
-
ip[
0]=
atoi(&g_SYS_Config.ServerIP[ServerIndex][
0]);
-
ip[
1]=
atoi(&g_SYS_Config.ServerIP[ServerIndex][
4]);
-
ip[
2]=
atoi(&g_SYS_Config.ServerIP[ServerIndex][
8]);
-
ip[
3]=
atoi(&g_SYS_Config.ServerIP[ServerIndex][
12]);
-
-
return
sprintf(pIpBuff,
"%d.%d.%d.%d",ip[
0],ip[
1],ip[
2],ip[
3]);
-
}
//这里面句柄什么的,发送接口什么的忽略掉,你只要知道打包方式,这个报文长度什么的非常重要。
-
/*************************************************************************************************************************
-
* 函数 : u16 POST_RealDataPackage(POST_HANDLE *pHandle, tm *pAcqTime,REAL_DATA *pData, u16 SerialNumber)
-
* 功能 : 实时数据打包(正文打包)
-
* 参数 : pHandle:句柄;AcqTime:观测时间;pData:实时数据指针;SerialNumber:流水号;AlarmStatus:报警定义
-
* 返回 : 长度
-
* 依赖 : 无
-
* 作者 : cp1300@139.com
-
* 时间 : 2018-02-04
-
* 最后修改时间 : 2018-02-04
-
* 说明 : 将报文打包写入到了pPackDataBuff中,注意:一定要在最后面增加一个换行符,这样每次发送数据时服务器才不会断开连接
-
*************************************************************************************************************************/
-
u16 POST_RealDataPackage(POST_HANDLE *pHandle,tm *pAcqTime,REAL_DATA *pData, u16 SerialNumber)
-
{
-
u16 len =
0;
-
char *pTextBuff = (
char *) pHandle->pPackDataBuff;
-
-
-
//报文格式 flag=1&ver=1.00&type=RealData&SERIAL=1&ST=1510260128&UT=2018-02-04 15:24:32&data={"ST":"1510260128","TT":"2018-02-04 18:00:00","Z":1.234,"VT":12.56,"ZT":128}
-
//http头与后面数据分开发送的时候,要先发送一个换行,但是这个换行不算总长度
-
len +=
sprintf(&pTextBuff[len],
"\r\n");
//前面增加一个换行-不要弄掉了,掉了会出现各种问题
-
len +=
sprintf(&pTextBuff[len],
"flag=%d&",
1);
//数据上传标识符1
-
len +=
sprintf(&pTextBuff[len],
"ver=%s&",POST_VER);
//通信协议版本,用于后续升级的兼容
-
len +=
sprintf(&pTextBuff[len],
"type=%s&",POST_REAL_DATA_STRING);
//报文类型:实时数据
-
len +=
sprintf(&pTextBuff[len],
"SERIAL=%d&",SerialNumber);
//流水号
-
len +=
sprintf(&pTextBuff[len],
"ST=%02X%02X%02X%02X%02X&",pHandle->SendDataTelAttr.TelNumber[
0],pHandle->SendDataTelAttr.TelNumber[
1],
-
pHandle->SendDataTelAttr.TelNumber[
2],pHandle->SendDataTelAttr.TelNumber[
3],pHandle->SendDataTelAttr.TelNumber[
4]);
//站点编号
-
len +=
sprintf(&pTextBuff[len],
"UT=%04d-%02d-%02d %02d:%02d:%02d&",timer.w_year, timer.w_month, timer.w_date, timer.hour, timer.min, timer.sec);
//发报时间
-
-
len +=
sprintf(&pTextBuff[len],
"data={");
//报文正文
-
//前面固定为ST 与 TT
-
len +=
sprintf(&pTextBuff[len],
"\"ST\":\"%02X%02X%02X%02X%02X\",",pHandle->SendDataTelAttr.TelNumber[
0],pHandle->SendDataTelAttr.TelNumber[
1],
-
pHandle->SendDataTelAttr.TelNumber[
2],pHandle->SendDataTelAttr.TelNumber[
3],pHandle->SendDataTelAttr.TelNumber[
4]);
//站点编号
-
len +=
sprintf(&pTextBuff[len],
"\"TT\":\"%04d-%02d-%02d %02d:%02d:%02d\",",pAcqTime->w_year, pAcqTime->w_month, pAcqTime->w_date, pAcqTime->hour, pAcqTime->min,
0);
//采集时间
-
//打包所有要素数据
-
len +=
JSON_RealDataPackage(&pTextBuff[len], pData, pAcqTime);
//实时数据打包为JSON(正文打包)
-
-
len +=
sprintf(&pTextBuff[len],
"}");
-
-
return len;
-
}
//上面是正文数据打包,自己根据需要实现json就行。
//下面就是发送了,先发送请求头,里面包含了报文正文的长度,请求头与报文正文之间有个换行,但是不算总长度,这个非常重要,没有控制好就会导致发送完成后服务器断开了,或者是不能收到服务器响应等各种情况
-
/*************************************************************************************************************************
-
* 函数 : POST_COMM_ERROR POST_SendRealDataPackge(POST_HANDLE *pHandle, tm *pAcqTime,REAL_DATA *pData, u16 SerialNumber)
-
* 功能 : 发送实时数据
-
* 参数 : pHandle:协议栈句柄;pConnectData:POST连接结构指针;pAcqTime:发报时间;pData:实时数据指针;SerialNumber:流水号;
-
* 返回 : RTU_ERROR
-
* 依赖 : 无
-
* 作者 : cp1300@139.com
-
* 时间 : 2018-02-01
-
* 最后修改时间 : 2018-02-01
-
* 说明 :
-
*************************************************************************************************************************/
-
POST_COMM_ERROR POST_SendRealDataPackge(POST_HANDLE *pHandle, tm *pAcqTime,REAL_DATA *pData, u16 SerialNumber)
-
{
-
u16 ByteNum =
0;
-
u8 retry ;
-
int len;
-
u16 ReceiveDelay;
-
u8 *pRxData;
//注意:接收数据的缓冲区与发送的一般是共用的,为了节省内存
-
-
if(SerialNumber ==
0)
//需要自动流水号
-
{
-
SerialNumber = pHandle->
SerialNumberAdd(pHandle->SendDataTelAttr.CentralIndex);
//流水号增加
-
}
-
-
for(retry =
0;retry < pHandle->SendRetry; retry ++)
//失败重试
-
{
-
ByteNum =
POST_RealDataPackage(pHandle, pAcqTime, pData, SerialNumber);
//数据正文打包
-
-
if(ByteNum <
2)
return POST_COMM_DATA_ERROR;
-
-
POST_SendHttpHead(pHandle, ByteNum
-2);
//发送http POST请求头-数据长度-2,去掉前面的2个换行符
-
uart_printf(
"正文(%dB):%s\r\n",ByteNum, (
char*)pHandle->pPackDataBuff);
-
OSTimeDlyHMSM(
0,
0,
0,
500);
//发送头部信息后延时500毫秒
-
pHandle->
pSendData(pHandle->pPackDataBuff, ByteNum);
//发送后续正文数据
-
-
//等待接收数据
-
len = pHandle->
pReadData(&pRxData,
20, pHandle->RxTimeOutMs, &ReceiveDelay);
//接收数据
-
if(len <
0)
-
{
-
uart_printf(
"[POST ERROR]:服务器异常的断开了连接\r\n");
-
return POST_COMM_LINGK_ERROR;
-
}
-
else
if(len <=
3)
-
{
-
uart_printf(
"[POST ERROR]:等待服务器返回数据超时\r\n");
-
continue;
-
}
-
else
-
{
-
-
pRxData[len] =
0;
//增加结束符
-
uart_printf(
"[POST]:服务器返回数据(%dms):\r\n%s\r\n", ReceiveDelay, pRxData);
-
-
return POST_COMM_OK;
-
}
-
}
-
-
uart_printf(
"[POST ERROR]:发送超时\r\n");
-
return POST_COMM_TIME_OUT;
-
}
//东西有点乱,只着重看请求头打包以及请求头发送与正文发送就行。
-
服务器上webapi核心,接收数据后进行判断,存储,响应操作
-
// POST api/rtu_datainterface
-
public HttpResponseMessage Post([FromBody]UploadDataStruct data)
-
{
-
//数据解析
-
try
-
{
-
if (data.flag !=
1 || data.type == null || data.SERIAL ==
0 || data.ST == null || data.ST.Length !=
10 || data.UT == null)
-
{
-
return null;
//数据无效
-
}
-
if (data.type ==
"RealData")
//上传实时数据
-
{
-
if (data.data != null)
-
SystemLog.
Write(data.ST +
" \t" + data.data);
-
-
//响应数据
-
return
new HttpResponseMessage
-
{
-
Content =
new
StringContent(
-
StaticJson.
DefaultResponseJsonStructPack(
1,
"1510260128", DateTime.Now.
ToString(
"yyyy-MM-dd hh:mm:ss")),
-
System.Text.Encoding.UTF8,
"application/json")
-
};
-
}
-
else
return null;
-
-
-
}
-
catch (Exception e)
-
{
-
return null;
-
}
-
-
-
}
//最后收到的数据
2018-03-18 07:57:34 2018030301 {"ST":"2018030301","TT":"2018-03-18 08:00:00","Z":3.098,"ZB":3.098,"SBL1":0.000,"SBL2":0.000,"VA":0.000,"VJ":0.000,"PD":0.0,"PJ":0.0,"PT":8.0,"PN01":0.0,"PN05":0.0,"PN10":0.0,"PN30":0.0,"P1":0.0,"DTEMP":15.4,"SIGNAL":40.0,"VT":12.19}
2018-03-18 08:07:37 2018030301 {"ST":"2018030301","TT":"2018-03-18 08:05:00","Z":3.098,"ZB":3.098,"SBL1":0.000,"SBL2":0.000,"VA":0.000,"VJ":0.000,"PJ":0.0,"PT":8.0,"PN01":0.0,"PN05":0.0,"DTEMP":15.5,"SIGNAL":62.0,"VT":12.21}
2018-03-18 08:07:39 2018030301 {"ST":"2018030301","TT":"2018-03-18 08:10:00","Z":3.099,"ZB":3.099,"SBL1":0.000,"SBL2":0.000,"VA":0.000,"VJ":0.000,"PJ":0.0,"PT":8.0,"PN01":0.0,"PN05":0.0,"PN10":0.0,"DTEMP":15.4,"SIGNAL":62.0,"VT":12.22}
2018-03-18 08:17:34 2018030301 {"ST":"2018030301","TT":"2018-03-18 08:15:00","Z":3.098,"ZB":3.098,"SBL1":0.000,"SBL2":0.000,"VA":0.000,"VJ":0.000,"PJ":0.0,"PT":8.0,"PN01":0.0,"PN05":0.0,"DTEMP":15.5,"SIGNAL":43.0,"VT":12.24}

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)