linux下gsoap環境搭建及C++ demo
第一次在Linux下裸寫程式碼,沒有大神可以抱大腿,makefile寫到吐血。
做一個從webservice服務端獲取資料的小東西。以下記錄環境搭建和基礎demo,資料整理彙總,備忘。
基礎概念
WebService:一種跨程式語言和跨作業系統平臺的遠端呼叫技術。能使得執行在不同機器上的不同應用無須藉助附加的、專門的第三方軟體或硬體, 就可相互交換資料或整合。依據Web Service規範實施的應用之間, 無論它們所使用的語言、 平臺或內部協議是什麼, 都可以相互交換資料。
soap:簡單物件訪問協議。SOAP協議 = HTTP協議 + XML資料格式。
gsoap
WSDL:自動生成的用來說明webService服務端可提供的服務資訊的檔案。
gsoap安裝
- 系統:centos6.8
- gsoap:2.8.69
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