1. 程式人生 > >linux下gsoap環境搭建及C++ demo

linux下gsoap環境搭建及C++ demo

第一次在Linux下裸寫程式碼,沒有大神可以抱大腿,makefile寫到吐血。
做一個從webservice服務端獲取資料的小東西。以下記錄環境搭建和基礎demo,資料整理彙總,備忘。

基礎概念

WebService:一種跨程式語言和跨作業系統平臺的遠端呼叫技術。能使得執行在不同機器上的不同應用無須藉助附加的、專門的第三方軟體或硬體, 就可相互交換資料或整合。依據Web Service規範實施的應用之間, 無論它們所使用的語言、 平臺或內部協議是什麼, 都可以相互交換資料。
soap:簡單物件訪問協議。SOAP協議 = HTTP協議 + XML資料格式。
gsoap

:是一種能夠把C/C++語言的介面轉換成基於soap協議的webservice服務的工具。
WSDL:自動生成的用來說明webService服務端可提供的服務資訊的檔案。


gsoap安裝

配合現場,安裝的全新centos,保證啥也沒得。(centos6.8居然還需要手動掛載硬碟,長見識了還)

1、下載解壓

壓縮包直接丟在/home下了

yum install unzip zip
unzip gsoap_2.8.69.zip

所以,gsoap的大本營就在/home/gsoap(解壓完的目錄)下了,對應修改makefile檔案的時候注意這點。

2、配置編譯環境

執行gsoap目錄下configure

cd /home/gsoap-2.8
./configure

3、編譯安裝

簡單來說就是

make
make install

make時會出現報錯,因為缺少依賴包,根據報錯資訊對應新增依賴即可。
- error: openssl/bio.h: No such file or directory

yum install openssl-devel
  • ylwrap: line 176: yacc: command not found
yum install byacc
  • missing: line 81: flex: command not found
yum install flex
  • /usr/bin/ld: cannot find -ly
yum install bison-devel

這類報錯以此類推找依賴即可,編譯成功的字很大,肯定能知道是成功了。

基礎demo

接下來會寫一個server做加法和減法。client呼叫(耍流氓,其實寫死了)。

這個例子的makefile寫的很酷,喜歡結構清晰。雖然更復雜的樣子,雖然今天還不會,還是喜歡這個demo,明天就會啦。

2018年8月29日過來填"明天就會啦"的坑:當前gsoap示例的makefile檔案說明

目錄結構如下:
calc
├─ bin
│ ├─ makefile
│ ├─ objects.mk
│ ├─ soap
│ │ └─ subdir.mk
│ ├─ sources.mk
│ └─ subdir.mk
├─ calc.h
├─ client.cpp
├─ server.cpp
├─ soap
│ ├─ calc.nsmap
│ ├─ calc.wsdl
│ ├─ ns.xsd
│ ├─ soapC.cpp
│ ├─ soapH.h
│ ├─ soapStub.h
│ ├─ soapcalcProxy.cpp
│ ├─ soapcalcProxy.h
│ ├─ soapcalcService.cpp
│ └─ soapcalcService.h

  • calc/bin:makefile及目標檔案目錄
  • calc/soap:gsoap根據server端給出的wsdl檔案或標頭檔案定義生成的中間檔案。
  • calc/calc.h:標頭檔案定義
  • calc/client.cpp:客戶端實現
  • calc/server.cpp:服務端實現(此處是為了測試)

1、生成客戶端和服務端所需的檔案

檔案放在calc/soap下
如果是根據wsdl檔案生成,則需要先使用wsdl2h生成標頭檔案。

wsdl2h -o calc.h calc.wsdl

wsdl2h常用指令如下:

-s 生成的標頭檔案不使用 STL
-o 檔名,指定輸出標頭檔案的名稱
-c 產生純 C 程式碼,否則是 C++ 程式碼
-t 檔名,指定 type map 檔案,預設是 typemap.dat

此處是直接自定義標頭檔案來生成,需要先建立標頭檔案:

cd /home/calc/
touch calc.h

檔案內容:

//gsoap ns service name: calc Simple calculator service
//gsoap ns service style: rpc
//gsoap ns service encoding: encoded
//gsoap ns service namespace: http://localhost/calc.wsdl
//gsoap ns service location: http://localhost/server.cgi
//gsoap ns schema namespace: urn:calc
int ns__add(double a, double b, double *result);
int ns__sub(double a, double b, double *result);

標頭檔案中給出的是服務端提供介面的宣告。

生成客戶端和服務端所需的檔案:

cd /home/calc/soap/
soapcpp2 -i -x ../calc.h

soapcpp2指令引數可以通過help檢視,此處不贅述。
soapcpp2常用指令如下:

-i 生成 C++ 包裝類,客戶端為 xxxProxy.h(.cpp),服務端為xxxService.h(.cpp)
-I 指定 import 的路徑,比如需要引入stlvector.h檔案來支援 STL vector 的序列化
-C 僅生成客戶端程式碼
-S 僅生成服務端程式碼
-c 產生純 C 程式碼,否則是 C++ 程式碼
-x 不要產生 XML 示例檔案
-L 不要產生soapClientLib.c和soapServerLib.c檔案

服務端和客戶端實現

server.cpp

#include "soap/soapcalcService.h"
#include "soap/calc.nsmap"
#include <iostream>
using namespace std;

int main(int argc, char **argv) {
    calcService calc;
    int port = 65531;

    if (calc.run(port)) {
        cerr << "Calc service run failed" << endl;
        exit(0);
    }
    return 0;
}

int calcService::add(double a, double b, double* result) {
    *result = a + b;
    return SOAP_OK;
}

int calcService::sub(double a, double b, double* result) {
    *result = a - b;
    return SOAP_OK;
}

client.cpp

#include "soap/soapcalcProxy.h"
#include "soap/calc.nsmap"
#include <iostream>
using namespace std;

int main(int argc, char **argv) {
    double a = 4;
    double b = 2;
    double result;
    calcProxy calc;
    calc.soap_endpoint = "http://localhost:65531";

    calc.add(a,b,&result);
    cout<<a<<"+"<<b<<"="<<result<<endl;

    calc.sub(a,b,&result);
    cout<<a<<"-"<<b<<"="<<result<<endl;
    return 0;
}

示例程式碼裡面把能寫死的都固定住了(笑哭),實際使用可調整為引數帶入。

編寫makefile檔案

/calc/bin/makefile

#檔案:makefile
RM := rm -rf

# 引入相關的生成檔案
-include sources.mk
-include subdir.mk
-include soap/subdir.mk
-include objects.mk

ifneq ($(MAKECMDGOALS),clean)
  ifneq ($(strip $(C++_DEPS)),)
    -include $(C++_DEPS)
  endif
  ifneq ($(strip $(C_DEPS)),)
    -include $(C_DEPS)
  endif
  ifneq ($(strip $(CC_DEPS)),)
    -include $(CC_DEPS)
  endif
  ifneq ($(strip $(SERVER_CPP_DEPS)),)
    -include $(SERVER_CPP_DEPS)
  endif
  ifneq ($(strip $(CLIENT_CPP_DEPS)),)
    -include $(CLIENT_CPP_DEPS)
  endif
  ifneq ($(strip $(CXX_DEPS)),)
    -include $(CXX_DEPS)
  endif
  ifneq ($(strip $(C_UPPER_DEPS)),)
    -include $(C_UPPER_DEPS)
  endif
endif

# 生成目標
all: server client

# 相關工具
server: $(SERVER_OBJS) $(USER_OBJS)
    @echo '建立目標: [email protected]'
    g++  -o"server" $(SERVER_OBJS) $(USER_OBJS) $(LIBS)
    @echo '完成建立目標: [email protected]'
    @echo "\n"

client: $(CLIENT_OBJS) $(USER_OBJS)
    @echo '建立目標: [email protected]'
    g++  -o"client" $(CLIENT_OBJS) $(USER_OBJS) $(LIBS)
    @echo '完成建立目標: [email protected]'
    @echo "\n"

# 清空臨時檔案
clean:
    -$(RM) $(SERVER_OBJS)$(CLIENT_OBJS)$(C++_DEPS)$(C_DEPS)$(CC_DEPS)$(SERVER_CPP_DEPS)$(CLIENT_CPP_DEPS)$(EXECUTABLES)$(CXX_DEPS)$(C_UPPER_DEPS)
    -@echo "\n"
cleanall:
    -$(RM) $(SERVER_OBJS)$(CLIENT_OBJS)$(C++_DEPS)$(C_DEPS)$(CC_DEPS)$(SERVER_CPP_DEPS)$(CLIENT_CPP_DEPS)$(EXECUTABLES)$(CXX_DEPS)$(C_UPPER_DEPS) server client
    -@echo "\n"
cleanexe:
    -$(RM) server client
    -@echo "\n"

.PHONY: all clean dependents cleanall cleanexe

/calc/bin/sources.mk

O_SRCS := 
SERVER_CPP_SRCS := 
CLIENT_CPP_SRCS :=
C_UPPER_SRCS := 
C_SRCS := 
S_UPPER_SRCS := 
OBJ_SRCS := 
ASM_SRCS := 
CXX_SRCS := 
C++_SRCS := 
CC_SRCS := 
SERVER_OBJS := 
CLIENT_OBJS :=
C++_DEPS := 
C_DEPS := 
CC_DEPS := 
SERVER_CPP_DEPS := 
CLIENT_CPP_SRCS :=
EXECUTABLES := 
CXX_DEPS := 
C_UPPER_DEPS := 

# 子目錄
SUBDIRS := \
soap \
. \

/calc/bin/subdir.mk

# 生成的相關引數
SERVER_CPP_SRCS += \
  ../server.cpp

SERVER_OBJS += \
  ./server.o 

SERVER_CPP_DEPS += \
  ./server.d 

CLIENT_CPP_SRCS += \
  ../client.cpp

CLIENT_OBJS += \
  ./client.o 

CLIENT_CPP_DEPS += \
  ./client.d 

# 根據.cpp檔案生成.o檔案
%.o: ../%.cpp
    @echo '建立目標: $<'
    g++ -O0 -g3 -Wall -DWITH_NONAMESPACES -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"[email protected]" "$<"
    @echo '完成建立目標: $<'
    @echo "\n"

/calc/bin/soap/subdir.mk (注意路徑哈,這樣是為了更方便地將soap的東西和我們自己寫的東西隔開,超喜歡這樣整理癖的存在~)

# 生成的相關引數
SERVER_CPP_SRCS += \
  ../soap/soapC.cpp \
  ../soap/soapcalcService.cpp \
  /home/gsoap-2.8/gsoap/stdsoap2.cpp

SERVER_OBJS += \
  ./soap/soapC.o \
  ./soap/soapcalcService.o \
  ./soap/stdsoap2.o

SERVER_CPP_DEPS += \
  ./soap/soapC.d \
  ./soap/soapcalcService.d \
  ./soap/stdsoap2.d 

CLIENT_CPP_SRCS += \
  ../soap/soapC.cpp \
  ../soap/soapcalcProxy.cpp \
  /home/gsoap-2.8/gsoap/stdsoap2.cpp

CLIENT_OBJS += \
  ./soap/soapC.o \
  ./soap/soapcalcProxy.o \
  ./soap/stdsoap2.o

CLIENT_CPP_DEPS += \
  ./soap/soapC.d \
  ./soap/soapcalcProxy.d \
  ./soap/stdsoap2.d 

# 根據.cpp檔案生成.o檔案
soap/%.o: ../soap/%.cpp
    @echo '建立目標: $<'
    g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"[email protected]" "$<"
    @echo '完成建立目標: $<'
    @echo "\n"

soap/%.o:/home/gsoap-2.8/gsoap/%.cpp
    @echo '建立目標: $<'
    g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"[email protected]" "$<"
    @echo '完成建立目標: $<'
    @echo "\n"

編譯執行測試

寫完bug當然是玩bug丫~

make
./server
./client