使用lacewing解决HTTP+XML接口问题

一、背景

        文章背景来源于十二五课题与西屋的SystematICS综合监控的接口问题,其中History Recorder服务部署为对外数据发布的接口。History Recorder服务允许SystematICS服务对象数据和列表数据配置成存储并转发给外系统处理软件。外系统处理软件需要在History Recorder中配置,这样综合监控软件可以监视它的连接状态。可以使用文件或者配置工具配置History Recorder服务,需要配置的信息主要有:

        •   表示数据要发送到的应用程序的路径;

        •   所要发送给应用程序的数据;

        •   所要发送给应用程序的表格。

        History Recorder服务使用HTTP协议向外系统发送数据,ISCS将根据配置主动连接到外系统的web服务,首次连接后将发送全部数据,之后将发送变化数据并定期更新全部数据。外系统的web服务需至少响应前3个http消息(回应200 OK)。

发送设备状态(数据点)的格式如下:

---------------http头------------------

POST / HTTP/1.1

host:192.10.36.36:808

content-location: oil://scada.TMS/hpx_prc_do_0000

content-type: application/calendar+xml

content-length:111

---------------data区------------------

<vjournal>

   <tags>bad</tags>

   <dtstart>2009-02-25T10:01:19.933723Z</dtstart>

   <description>1</description>

</vjournal>

---------------结束------------------

    发送数据时是以XML包封装内容,基于这些情况描述,西屋的对外接口类似SOAP协议。

二、Lacewing

        这篇文章主要讲述怎样把Web Server集成到你的Win32 C++应用中。使用lacewing网络库编写的C++ Web应用程序具有更快的速度和良好的伸缩性,占用系统资源极低。liblacewing 是一个跨平台的高级网络库,用于C和C++。旨在提供一组直观的Socket通讯类,侧重于稳定性和平台优化(支持IOCP, epoll 和kqueue)。

        Lacewing::Webserver 作为一个功能强大的HTTP server, 主要有以下特征:

        •HTTP GET/POST with automatic parameter parsing

        •Non-blocking file sending

        •Cookies and sessions

        •Multipart file upload

        •Getting/setting the last modified date, to easily implement caching

        •Full HTTPS support

        Lacewing源代码:http://lacewing-project.org/

三、测试环境

1、 操作系统

         WINDOWS 7

2、系统

         处理器:Intel(R) Core(TM) i5-2401M CPU @ 2.30GH 2.30GH

         安装内存:3.00GB (2.88 GB可用)

         系统类型:32位操作系统

3、工具环境

         A、vc++6.0

         B、VS2008

四、创建Web Server Project

        下载Lacewing源代码,使用VS2008编译之后会在bin目录下产生lacewind.dll和lacewing.lib。

        使用VS2008创建一个testWebServer WIN32控制台工程。同时,把lacewind.dll和lacewing.lib复制到工程文件目录下,在工程属性中配置包含lacewing.lib文件。

// testWebServer.cpp : Defines the entry point for the console application.
//
#include "lacewing.h"

#include <assert.h>
#include <string.h>

#import <msxml4.dll>

using namespace MSXML2;
void PaserXml(BSTR bstXML)
{
    MSXML2::IXMLDOMDocumentPtr pDoc;
    HRESULT hr;
	
	hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));
    if (FAILED(hr))
    {  
        printf("无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!");
        return ;
    }
    try
    { 
		// 加载文件
		// pDoc->load("test.xml");
		pDoc->loadXML(bstXML);
		long lChilds, i;
		
		// 根节点
		MSXML2::IXMLDOMElementPtr pRootElement = pDoc->GetdocumentElement();
		printf("root = %s\n", (char *)pRootElement->GetnodeName());
		
		// 根节点的一级子节点
		MSXML2::IXMLDOMNodeListPtr pNodeList = pRootElement->GetchildNodes();
		lChilds = pNodeList->Getlength();
		char szNodeName[48], szValue[64];
		for (i = 0; i < lChilds; i++)
		{
			MSXML2::IXMLDOMNodePtr pNode = pNodeList->Getitem(i);
			// 过滤注释节点
			if (pNode->GetnodeType() != MSXML2::NODE_COMMENT)
			{
				BSTR bstrNodeName = pNode->GetnodeName();		
				char *lpszNodeName = _com_util::ConvertBSTRToString(bstrNodeName);					strncpy(szNodeName, lpszNodeName, sizeof(szNodeName));
				delete []lpszNodeName;
				
				BSTR bstrValue = pNode->Gettext();
				char *lpszValue = _com_util::ConvertBSTRToString(bstrValue);
				strncpy(szValue, lpszValue, sizeof(szValue));
				delete []lpszValue;			
				
				printf("%s:%s\n", szNodeName, szValue);
			}
		}
	}
	catch (_com_error &e)
    {
		printf("Description = '%s'\n", (char*)e.Description());       
		if (pDoc)
		{
            pDoc.Release();
		}        
    }
}

void onGet(Lacewing::Webserver &, Lacewing::Webserver::Request &Request)
{
    /* The MIME type defaults to "text/html" */
    Request.SetMimeType("text/html"); 
    Request.WriteFile("post.html");
}

Void onPost(Lacewing::Webserver &Webserver, Lacewing::Webserver::Request &Request)
{
	// 这里szBody将显示HttpPost发送的XML格式化数据
	//<vjournal>
	//   <tags>bad</tags>
	//   <dtstart>2009-02-25T10:01:19.933723Z</dtstart>
	//   <description>1</description>
	//</vjournal>
	char *szBody = (char *)Request.Body();
	BSTR bstrBody = _com_util::ConvertStringToBSTR(szBody);			
	PaserXml(bstrBody);
	::SysFreeString(bstrBody);	
	Request << "Hello SystematICS!";
	
	struct Lacewing::Webserver::Request::Header * Header = NULL;
    for (Header = Request.FirstHeader(); Header; Header = Header->Next())
    {
       	const char *szName = Header->Name();
	const char *szValue = Header->Value();
    }
    
    Lacewing::Webserver::Request::Parameter *p = NULL;
    for (p = Request.POST(); p; p = p->Next())
    {
	const char *szName = p->Name();
	const char *szValue = p->Value();
    }
}

int main(int argc, char * argv[])
{
    CoInitialize(NULL);
	
    Lacewing::EventPump EventPump;
    Lacewing::Webserver Webserver(EventPump);
	
    Webserver.onGet(onGet);
    Webserver.onPost(onPost);
    Webserver.Host(8080);
    
    EventPump.StartEventLoop();
	
    CoUninitialize();
    return 0;
}

五、创建HTTP Post Project

       使用VS6创建一个testHttpPost WIN32控制台工程。

// testHttpPost.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string>
#include <iostream>
#import <msxml4.dll>

using namespace MSXML2;

std::wstring GenerateData()
{
	std::wstring wvarQuery;
	IXMLDOMDocumentPtr pDoc;
	IXMLDOMElementPtr xmlRoot;
	
	// 创建DOMDocument对象
	HRESULT hr = pDoc.CreateInstance(__uuidof(DOMDocument40));
	if (!SUCCEEDED(hr))
	{  
		printf("无法创建DOMDocument对象,请检查是否安装了MS XML Parser运行库!");
		return wvarQuery;
	}
	
	// 根节点的名称为vjournal
	// 创建元素并添加到文档中
	xmlRoot = pDoc->createElement("vjournal");
	
	pDoc->appendChild(xmlRoot);
	IXMLDOMElementPtr pNode;
	
	// 添加“tags”元素
	pNode = pDoc->createElement("tags");
	pNode->Puttext((const char *)"bad");
	xmlRoot->appendChild(pNode);
	
	// 添加“dtstart”元素
	pNode = pDoc->createElement("dtstart");
	pNode->Puttext((const char *)"2009-02-25T10:01:19.933723Z");
	xmlRoot->appendChild(pNode);

	// 添加“description”元素
	pNode = pDoc->createElement("description");
	pNode->Puttext((const char *)"1");
	xmlRoot->appendChild(pNode);
	
	// 保存到文件,如果存在就覆盖,否则不存在就建立.
	// pDoc->save("test.xml");
	wvarQuery = pDoc->Getxml(); 
	return wvarQuery;
}

void PaserXml(BSTR bstXML)
{
    IXMLDOMDocumentPtr pDoc;
    HRESULT hr;
    hr = pDoc.CreateInstance(__uuidof(DOMDocument40));
    if (FAILED(hr))
    {  
        printf("无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!");
        return ;
    }
    
    // 加载文件
    // pDoc->load("test.xml");
    // 加载内存
    pDoc->loadXML(bstXML);
	long lChilds, i;
	
	// 根节点
	IXMLDOMElementPtr pRootElement = pDoc->GetdocumentElement();
    printf("root = %s\n", (char *)pRootElement->GetnodeName());

    // 根节点的一级子节点
    IXMLDOMNodeListPtr pNodeList = pRootElement->GetchildNodes();
    lChilds = pNodeList->Getlength();
    char szNodeName[48], szValue[64];
    for (i = 0; i < lChilds; i++)
    {
        IXMLDOMNodePtr pNode = pNodeList->Getitem(i);
		// 过滤注释节点
		if (pNode->GetnodeType() != NODE_COMMENT)
		{
			BSTR bstrNodeName = pNode->GetnodeName();		
			char *lpszNodeName = _com_util::ConvertBSTRToString(bstrNodeName);			
			strncpy(szNodeName, lpszNodeName, sizeof(szNodeName));
			delete []lpszNodeName;

			BSTR bstrValue = pNode->Gettext();
			char *lpszValue = _com_util::ConvertBSTRToString(bstrValue);
			strncpy(szValue, lpszValue, sizeof(szValue));
			delete []lpszValue;			

			printf("%s:%s\n", szNodeName, szValue);
        }
    }
}


void SendData(std::wstring url)
{
    long lState, lStatus;
    HRESULT hr;
    IXMLHTTPRequestPtr pIXMLHTTPRequest;
    IXMLDOMDocumentPtr pXMLDoc;

    try
    {        
        hr = pIXMLHTTPRequest.CreateInstance(__uuidof(XMLHTTP));
        SUCCEEDED(hr) ? 0 : throw hr;

        hr = pIXMLHTTPRequest->open("POST", url.c_str(), false);
        SUCCEEDED(hr) ? 0 : throw hr;
        // 如果要向服务器post数据,这个地方一定要设置为application/x-www-form-urlencoded
        pIXMLHTTPRequest->setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

		std::wstring wvarQuery = GenerateData();
		_variant_t vartQueryFields(wvarQuery.c_str());

		PaserXml(vartQueryFields.bstrVal);

		hr = pIXMLHTTPRequest->send(vartQueryFields);
	
         SUCCEEDED(hr) ? 0 : throw hr;
         // 处理返回的xml数据,对返回的xml数据进行解析,主要是dom方法.
         pXMLDoc = pIXMLHTTPRequest->responseXML;
	
		// Retrieve the state
		pIXMLHTTPRequest->get_readyState(&lState);
		if (lState == 4)
		{
			// The request has completed.
			// Get the request status.
			pIXMLHTTPRequest->get_status(&lStatus);			
			if (lStatus == 200)
			{
				// Get the response body if we were successful.
				BSTR bstrbody;
				pIXMLHTTPRequest->get_responseText(&bstrbody);			
				char *lpszBody = _com_util::ConvertBSTRToString(bstrbody);
				// 这里将显示WebServer body区的数据“Hello SystematICS!”
				delete []lpszBody;
			} 
		}
    }
    catch (_com_error &e)
    {
		printf("Description = '%s'\n", (char*)e.Description());
         if (pIXMLHTTPRequest)
		{
			pIXMLHTTPRequest.Release();
		}
         if (pXMLDoc)
		{
            pXMLDoc.Release();
		}        
    }
}

int main(int argc, char* argv[])
{
	CoInitialize(NULL);
     SendData(L"http://localhost:8080");
	CoUninitialize();
     return 0;
}

六、测试

1)、HTTP CLIENT发送:

POST / HTTP/1.1

Accept: */*

Accept-Language: zh-cn

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)

Host: localhost:8080

Content-Length: 113

Connection: Keep-Alive

Cache-Control: no-cache

 

<vjournal><tags>bad</tags><dtstart>2009-02-25T10:01:19.933723Z</dtstart><description>1</description></vjournal>

 

注意:文本最后是“\r\n\r\n两个回车换行结束。

2)、HTTP SERVER接收:

POST / HTTP/1.1

Accept: */*

Accept-Language: zh-cn

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)

Host: localhost:8080

Content-Length: 113

Connection: Keep-Alive

Cache-Control: no-cache

 

<vjournal><tags>bad</tags><dtstart>2009-02-25T10:01:19.933723Z</dtstart><description>1</description></vjournal>

 

注意:文本最后是“\r\n\r\n两个回车换行结束。

3)、HTTP SERVER响应: "HTTP/1.1 200 OK\r\nContent-Length:0\r\n\r\n"

即:

HTTP/1.1 200 OK

Content-Length:0

 

注意:文本最后是“\r\n\r\n两个回车换行结束。长度为0表示BODY为空字符串。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值