当前位置:首页 > > 充电吧
[导读]HTTP请求是依赖TCP的,也就是在单片机上面,我们一样可以使用,无非就是先发送一个http请求头,再发送正文,比如我最近就使用了http post方式发送数据到服务器,服务器端使用的是WEB API

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.1rn
Content-Type: application/x-www-form-urlencoded; charset=UTF-8rn
X-Requested-With: XMLHttpRequestrn
Host: %srn
Content-Length: %drn
Expect: 100-continuern
Connection: Keep-Alivern" //最后面必须空一行
}

//发送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未初始化rn");
	
	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):%srn",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],"rn");								//前面增加一个换行-不要弄掉了,掉了会出现各种问题
	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):%srn",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]:服务器异常的断开了连接rn");
			return POST_COMM_LINGK_ERROR;
		}
		else if(len <= 3)
		{
			uart_printf("[POST ERROR]:等待服务器返回数据超时rn");
			continue;
		}
		else 
		{
			
			pRxData[len] = 0;	//增加结束符
			uart_printf("[POST]:服务器返回数据(%dms):rn%srn", ReceiveDelay, pRxData);
			
			return POST_COMM_OK;
		}
	}
	
	uart_printf("[POST ERROR]:发送超时rn");
	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}


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭