动环监控系统简述
1.术语介绍
1.1 省集中监控中⼼-Province Supervision Center(PSC)
⾯向多FSU管理的⾼级监控层次,即省集中监控中⼼,通过开放的数据协议,连接监控范围内的FSU。1.2 现场监控单元-Field supervision unit(FSU)
监控系统的最⼩管理⼦系统,由若⼲监控模块和其它辅助设备组成,⾯向直接的设备数据采集、处理的监控层次,可以包含采样、数据处理、数据中继等功能,监控范围⼀般为⼀个独⽴的通信局(站)或⼤型局(站)内相对独⽴的电源、空调设备及环境。1.3 监控对象 Supervision Object(SO)被监控的各种电源、空调设备及机房环境。1.4 B接⼝
为省集中监控中⼼(PSC)与现场监控单元(FSU)之间的接⼝。(即FSU的北向接⼝)
2. 接⼝⽹络结构
FSU与PSC之间通过WebService和FTP⽅式互联,⼆者同时形成完整的B接⼝协议标准。
B接⼝在嵌⼊式arm监控主机上的实现
环境
宿主机平台:Ubuntu 16.04.6⽬标机平台:iMX6UL
交叉编译:gcc-linaro-4.9-2014.11 arm-linux-gnueabihf-gcc SOAP/XML 关于C/C++ 语⾔的实现 gsoap_2.8.83 XML数据的⽣成和解析 XML数据的⽣成和解析 libxml2 结合主要开发为C环境且尽量占⽤较少资源,推荐使⽤minixmlXML数据的⽣成和解析 minixml
1. gsaop ⽣成 B接⼝报⽂协议 C代码框架
gSOAP编译⼯具提供了⼀个SOAP/XML 关于C/C++ 语⾔的实现,从⽽让C/C++语⾔开发web服务或客户端程序的⼯作变得轻松了很多。绝⼤多数的C++web服务⼯具包提供⼀组API函数类库来处理特定的SOAP数据结构,这样就使得⽤户必须改变程序结构来适应相关的类库。与之相反,gSOAP利⽤技术提供了⼀组透明化的SOAP API,并将与开发⽆关的SOAP实现细节相关的内容对⽤户隐藏起来。1.1 gsaop在linux下的安装gsoap安装编译依赖
sudo apt-get install build-essential libgtk2.0-dev libglib2.0-dev checkinstall m4 flex bison automake autoconf openssl libssl-dev
为了成功编译gSOAP,您需要安装GTK+的开发⽂件和GLib库(libraries)。
安装Checkinstall以便管理您系统中直接由源代码编译安装的软件。
安装YACC,YACC是Unix/Linux上⼀个⽤来⽣成编译器的编译器(编译器代码⽣成器),sudo apt-get install flex bison安装OpenSSL,web通信的加密(https)及鉴权 sudo apt-get install openssl libssl-dev
安装编译步骤: 解压
unzip gsoap_2.8.83.zipmkdir gsoap_installcd gsoap-2.8/
配置安装路径、编译、安装
./configure --prefix=/home/wangh/workspace/wh_tools/gsoap_installsudo make
sudo make install
使⽤gsoap⽣成 fsu 代码框架
新建gsoap_fsu⽂件夹,从gsoap_install⽂件夹中拷贝以下⽂件bin/soapcpp2 bin/wsdl2hgsoap2.8/gsoap/typemap.datcustom和import⽂件夹
1.使⽤wsdl2h⼯具,根据WSDL产⽣头⽂件,执⾏以下命令
./wsdl2h -P -x -c -s -t ./typemap.dat -o fsu.h FSUService.wsdl
其中-c为产⽣纯c代码,默认⽣成 c++代码;
-x 不产⽣xml⽂件(可⽤可不⽤,xml有⼀定帮助,但是太多);-s为不使⽤STL库,-t为typemap.dat的标识。详情可通过wsdl2h.exe -help查看帮助。
这⾥的WSDL⽂件,可以在wsdl2h命令中在线下载,也可以先下载到本地,然后引⽤本地WSDL⽂件,我这⾥是采⽤本地⽂件⽅式。
2. 使⽤soapcpp2⼯具,根据头⽂件 fsu.h 产⽣框架代码,执⾏以下命令
./soapcpp2 -2 -L -c -x -I import:custom fsu.h
-2 ⽣成 SOAP 1.2
-L 不⽣成客户端、服务器库⽂件-c 为产⽣纯c代码,默认⽣成 c++代码-I path 引⽤⽂件路径
3. 提取有效核⼼代码⽤于应⽤编程,应⽤⼯程使⽤⽂件如下:
2. B接⼝报⽂协议分析与实现
2.1 SOAP函数接⼝分析
根据 FSUService.wsdl ⽣成 soap API 如下,在 soapStub.h 的最后定义
我们不⽤去关⼼ SOAP 接⼝的实现细节,直接调⽤对应 API 即可实现客户端与服务器的 xml 数据收发。客户端接⼝过程:
soap_call_ns1__invoke() 在客户端调⽤,实现发送和接收(它调⽤send和recv);服务器接⼝过程:
soap_serve() 服务器调⽤,部署 SOAP 服务器,它会调⽤soap_serve_request(),当收到 ns1:invoke 的请求时,服务器调⽤ soap_serve_ns1__invoke(),在调⽤应⽤层⽤户接⼝ ns1__invoke(),来获取接收数据和填充应答数据。2.2 SOAP通信简单⽰例 我的⼯程⽬录如下图所⽰:
客户端程序:
/**
*********************************************************************************** @file main.c
* @brief soap客户端测试程序
* @details 基于东环监控 B 接⼝的soap客户端程序
* @author wanghuan any question please send mail to 371463817@qq.com* @date 2019-06-17* @version V1.0
* @copyright Copyright (c) 2019-2022 江苏亨通光⽹科技有限公司***********************************************************************************/
#include \"soapH.h\"#include \"stdsoap2.h\"#include #include \"FSUServiceSoapBinding.nsmap\"int main(int argc, char **argv){ // struct soap fsuSoap;// soap_init(&fsuSoap); struct soap *fsuSoap = soap_new(); fsuSoap->send_timeout = fsuSoap->recv_timeout = 5; //soap发送、接收超时 fsuSoap->transfer_timeout = 30; //soap消息传输超时 soap_set_namespaces(fsuSoap, namespaces);// soap_set_mode(fsuSoap, SOAP_C_NOIOB); struct ns1__invokeResponse soap_tmp_ns1__invokeResponse; char * soap_tmp_SOAP_ENC__string; soap_default_ns1__invokeResponse(fsuSoap, &soap_tmp_ns1__invokeResponse); soap_tmp_SOAP_ENC__string = NULL; soap_tmp_ns1__invokeResponse._invokeReturn = &soap_tmp_SOAP_ENC__string; // ⼿动组成LOGIN的xml数据字符串 char xmlData[500]; memset(xmlData, 0x00, sizeof(xmlData)); strcat(xmlData, \"\\n\"); strcat(xmlData, \" strcat(xmlData, \" strcat(xmlData, \" strcat(xmlData, \" printf(\"soap_tmp_ns1__invoke._xmlData:\\n\"); printf(\"%s\", xmlData); // saop 客户端程序 // char * server_addr = \"http://10.10.62.83:8080/HT_SC/services/SCService\"; char * server_addr = \"http://192.168.1.123:8080\"; int iRet = soap_call_ns1__invoke(fsuSoap, server_addr, NULL, xmlData, soap_tmp_ns1__invokeResponse._invokeReturn); if ( iRet == SOAP_ERR) { printf(\"Error while calling the soap_call_ns1__invoke\"); } else { printf(\"Calling the soap_call_ns1__invoke success。\\n\"); printf(\"%s\\n\", *soap_tmp_ns1__invokeResponse._invokeReturn); } return 0;} 服务端程序: /** *********************************************************************************** @file main.c * @brief soap服务端测试程序 * @details 基于东环监控 B 接⼝的soap服务器程序 * @author wanghuan any question please send mail to 371463817@qq.com* @date 2019-06-17* @version V1.0 * @copyright Copyright (c) 2019-2022 江苏亨通光⽹科技有限公司***********************************************************************************/ #include \"soapH.h\"#include \"stdsoap2.h\"#include #include \"FSUServiceSoapBinding.nsmap\" /** * 启动soap服务器*/ int main(int argc, char **argv){ SOAP_SOCKET iSocket_master, iSocket_slave; struct soap *fsuSoap = soap_new(); //新建soap fsuSoap->send_timeout = fsuSoap->recv_timeout = 5; //soap发送、接收超时 fsuSoap->transfer_timeout = 30; //soap消息传输超时// soap_set_mode(fsuSoap, SOAP_C_NOIOB); // saop 服务器程序 8080为端⼝号,最后⼀个参数不重要。 iSocket_master = soap_bind(fsuSoap, NULL, 8080, 100); //绑定到相应的IP地址和端⼝()NULL指本机,然后监听 if (iSocket_master< 0) //绑定出错 { soap_print_fault(fsuSoap, stderr); exit(-1); } printf(\"SoapBind success,the master socket number is:%d\\n\",iSocket_master); //绑定成功返回监听套接字 while(1) { iSocket_slave = soap_accept(fsuSoap); //收到套接字连接 if(iSocket_slave < 0) { soap_print_fault(fsuSoap, stderr); exit(-1); } //客户端的IP地址 fprintf(stderr,\"Accepted connection fromIP= %d.%d.%d.%d socket = %d \\n\", \\ ((fsuSoap->ip)>>24)&&0xFF,((fsuSoap->ip)>>16)&0xFF,((fsuSoap->ip)>>8)&0xFF,(fsuSoap->ip)&0xFF,(fsuSoap->socket)); printf(\"Socket connect success,the slave socket number is:%d\\n\",iSocket_slave); soap_serve(fsuSoap); printf(\"soap_serve end...\"); soap_end(fsuSoap); //服务器出错才到这⼀步 } soap_done(fsuSoap); free(fsuSoap); return 0;} /** * soap服务器⽤户数据处理函数 * @param[in] *_xmlData 接收客户端的xml格式字符串* @param[out] **_invokeReturn 服务器要回复⼤数据* @return SOAP_OK or error code*/ SOAP_FMAC5 int SOAP_FMAC6 ns1__invoke(struct soap* soap, char *_xmlData, char **_invokeReturn){ printf(\"ns1__invoke _xmlData\\n\"); printf(\"%s\\n\", _xmlData); char xmlData[500]; memset(xmlData, 0, sizeof(xmlData)); strcat(xmlData, \"\\n\"); strcat(xmlData, \" strcat(xmlData, \" strcat(xmlData, \" *_invokeReturn = xmlData; // *_invokeReturn = \"\\n 程序makefile: 顶层Makefile与Makefile.inc DIRS := DIRS += sc_clientDIRS += sc_server#DIRS += xml_test # Dummy targets for building and clobbering everything in all subdirectoriesall: @ for dir in ${DIRS}; do (cd $${dir}; ${MAKE}) ; doneclean: @ for dir in ${DIRS}; do (cd $${dir}; ${MAKE} clean) ; done Makefile.inc SHELL = /bin/bash#CC := gcc -m32#CPP := g++#LD := ld#AR := ar#STRIP := strip CC := arm-linux-gnueabihf-gccCPP := arm-linux-gnueabihf-g++LD := arm-linux-gnueabihf-ldAR := arm-linux-gnueabihf-arSTRIP := arm-linux-gnueabihf-strip # -DWITH_DOM -DWITH_OPENSSL两个宏是链接openssl时要⽤的; # -DDEBUG宏⽤于开启SOAP协议收发⽇志,⽇志存于⽂件RECV.log、SENT.log、TEST.log之中CFLAGS += -c -g -Wall #CFLAGS += -DWITH_DOM -DWITH_OPENSSLCFLAGS += -std=gnu99 CFLAGS += -DWITH_NO_C_LOCALE#CFLAGS += -WITH_NONAMESPACESCFLAGS += $(INCLUDE)# openssl⽬录名OPENSSL_DIR := #OPENSSL_DIR += ../openssl # 源⽂件 SOURCES_FSU := SOURCES_FSU += ../soap_sc/soapC.cSOURCES_FSU += ../soap_sc/soapClient.c#SOURCES_FSU += ../soap_sc/soapServer.cSOURCES_FSU += ../soap_sc/stdsoap2.cSOURCES_COMM := # ⽬标⽂件 OBJECTS_FSU := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES_FSU))) OBJECTS_COMM := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES_COMM)))# 头⽂件路径 INCLUDE += -I../soap_sc/ \\ -I../minixml/ \\ # -I../libxml2/include \\# -I../tinyxml2/ \\# -I../comm/ \\ # -I$(OPENSSL_DIR)/include \\# 共享库链接OpenSSL #LDLIBS += -L$(OPENSSL_DIR)/lib \\# -lssl \\# -lcrypto \\ # 静态库链接OpenSSL #LDLIBS += $(OPENSSL_DIR)/lib/libssl.a \\# $(OPENSSL_DIR)/lib/libcrypto.a \\# -ldl \\ # 静态库链接libxml2 #LDLIBS += ../libxml2/libxml2.a \\# -lm # 静态库链接minixml LDLIBS += ../minixml/libmxml.a#LDLIBS += -lmxml # 链接库(其他) LDLIBS += -lpthread %.o: %.cpp @echo \" CPP \" $@; @$(CPP) $(CFLAGS) -c -o $@ $<%.o: %.c @echo \" CC \" $@; @$(CC) $(CFLAGS) -c -o $@ $<.PHONY: all clean 客户端client的Makefile include ../Makefile.incPROGRAM = fsucSOURCES += main.c OBJECTS := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES))) all: $(OBJECTS_FSU) $(OBJECTS_COMM) $(OBJECTS) $(CC) -o $(PROGRAM) $(OBJECTS_FSU) $(OBJECTS_COMM) $(OBJECTS) $(LDLIBS)clean: rm -f $(OBJECTS_FSU) rm -f $(OBJECTS_COMM) rm -f $(OBJECTS) rm -f $(PROGRAM) 编译之后 先执⾏服务端程序,在执⾏客户端程序服务端收到request 客户端发送request,并收到response 接下来开始尝试使⽤ libxml2 库⽣成和解析 xml 2.3 libxml2安装移植(改⽤minixml)新建安装⽂件夹,这样⽅便我们提取库⽂件使⽤ mkdir /home/wangh/workspace/wh_tools/libxml-install 编写安装及配置脚本 wh_configure.sh 如下: #!/bin/sh #sh⽂件需设置可执⾏权限 chmod +x wh_configure.sh#--prefix=PATH,指定make install时⽬标⽂件存放路径PREFIX=/home/wangh/workspace/wh_tools/libxml-install#--host=target-platform 指定⽬标平台HOST=arm-linux#交叉编译绝对路径 CC_DIR=/home/wangh/Tools/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc#编译配置 #sudo ./configure --prefix=$PREFIX --host=$HOST CC=$CC_DIR --with-python=/home/wangh/workspace/wh_tools/libxml2-2.9.9/python #编译时由于提⽰没有python相关的头⽂件出错,⼜因为项⽬中不使⽤python相关的内容,所以没有讲python进库中,读者应该按照⾃⼰的需要要配置该选项。对于zlib同样的道理,--without-zlib不添加会编译出错sudo ./configure --prefix=$PREFIX --host=$HOST --target=arm CC=$CC_DIR --without-zlib --without-pythonsudo make sudo make install 执⾏安装脚本2.4 minixml安装移植 是⼀个⼩型的开源的XML解析器,采⽤ C 语⾔开发。该解析器最⼤的特点就是⼩型、⽆须依赖其他类库,在嵌⼊式系统中,minixml解析器很⼩巧(200k多点),很常⽤。 待续。。。。。 因篇幅问题不能全部显示,请点此查看更多更全内容