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

来源:互联网 发布:phxsql mysql 5.7 编辑:程序博客网 时间:2024/06/07 05:44

一、背景

        文章背景来源于十二五课题与西屋的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 statepIXMLHTTPRequest->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为空字符串。

 

原创粉丝点击