動環監控系統中B接口的實現


動環監控系統簡述

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        https://www.linaro.org/downloads/

SOAP/XML 關於C/C++ 語言的實現    gsoap_2.8.83      https://sourceforge.net/projects/gsoap2/files/

XML數據的生成和解析       tinyxml2

XML數據的生成和解析   libxml2   ftp://xmlsoft.org/libxml2/

結合主要開發為C環境且盡量占用較少資源,推薦使用minixml

XML數據的生成和解析      minixml   https://www.msweet.org/mxml/


 

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.zip
mkdir gsoap_install
cd gsoap-2.8/

配置安裝路徑、編譯、安裝

./configure --prefix=/home/wangh/workspace/wh_tools/gsoap_install
sudo make
sudo make install

 

使用gsoap生成 fsu 代碼框架

新建gsoap_fsu文件夾,從gsoap_install文件夾中拷貝以下文件

bin/soapcpp2        bin/wsdl2h

gsoap2.8/gsoap/typemap.dat

custom和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 <stdio.h>
#include <stdlib.h>
#include <assert.h>
#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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    strcat(xmlData, "<Request>\n");
    strcat(xmlData, "<PK_Type>\n");
    strcat(xmlData, "<Name>LOGIN</Name>\n");
    strcat(xmlData, "</PK_Type>\n");
    strcat(xmlData, "<Info>\n");
    strcat(xmlData, "<UserName>123</UserName>\n");
    strcat(xmlData, "<PassWord>123</PassWord>\n");
    strcat(xmlData, "<FsuId>10004</FsuId>\n");
    strcat(xmlData, "<FsuIP>192.168.1.124</FsuIP>\n");
    strcat(xmlData, "<FsuPort>10000</FsuPort>\n");
    strcat(xmlData, "</Info>\n");
    strcat(xmlData, "</Request>\n");

    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 <stdio.h>
#include <stdlib.h>
#include <assert.h>
#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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    strcat(xmlData, "<Response>\n");
    strcat(xmlData, "<PK_Type>\n");
    strcat(xmlData, "<Name>LOGIN_ACK</Name>\n");
    strcat(xmlData, "</PK_Type>\n");
    strcat(xmlData, "<Info>\n");
    strcat(xmlData, "<RightLevel/>\n");
    strcat(xmlData, "</Info>\n");
    strcat(xmlData, "</Response>");

    *_invokeReturn = xmlData;
//    *_invokeReturn = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n<PK_Type>\n<Name>LOGIN_ACK</Name>\n</PK_Type>\n<Info>\n<RightLevel/>\n</Info>\n</Response>";

    printf("_invokeReturn _xmlData\n");
    printf("%s\n", *_invokeReturn);
    return SOAP_OK;
}

 

程序makefile:

頂層Makefile與Makefile.inc

DIRS := 
DIRS += sc_client
DIRS += sc_server
#DIRS += xml_test


# Dummy targets for building and clobbering everything in all subdirectories

all:     
    @ for dir in ${DIRS}; do (cd $${dir}; ${MAKE}) ; done

clean: 
    @ 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-gcc
CPP          := arm-linux-gnueabihf-g++
LD           := arm-linux-gnueabihf-ld
AR           := arm-linux-gnueabihf-ar
STRIP        := 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_OPENSSL
CFLAGS += -std=gnu99
CFLAGS += -DWITH_NO_C_LOCALE
#CFLAGS += -WITH_NONAMESPACES
CFLAGS += $(INCLUDE)

# openssl目錄名
OPENSSL_DIR :=
#OPENSSL_DIR += ../openssl


# 源文件
SOURCES_FSU :=
SOURCES_FSU += ../soap_sc/soapC.c
SOURCES_FSU += ../soap_sc/soapClient.c
#SOURCES_FSU += ../soap_sc/soapServer.c
SOURCES_FSU += ../soap_sc/stdsoap2.c

SOURCES_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.inc

PROGRAM = fsuc

SOURCES += 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-python
sudo make
sudo make install

執行安裝腳本

2.4 minixml安裝移植

是一個小型的開源的XML解析器,采用 C 語言開發。該解析器最大的特點就是小型、無須依賴其他類庫,在嵌入式系統中,minixml解析器很小巧(200k多點),很常用。

 

待續。。。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM