此博文僅限於自己參考使用,描述不恰當之處請見諒
編寫頭文件:add.h
在這裏我們不需要wsdl的文件,可以直接從.h文件來生成代碼其生成的.h並不能直接用,是被soapcpp2用來解釋生成soap框架代碼的。我們定義一個函數聲明文件,用來定義接口函數,名稱爲add.h
#ifndef _ADDH_
#define _ADDH_
int ns2_add(int num1,int num2,int *sum);
#endif
我們執行一下命令,自動生成一些遠程調用需要的文件。
拷貝 /home/qinyisong/gsoap_x386/bin/soapcpp2到所需文件夾
soapcpp2 -c add.h -I /home/qinyisong/gsoap_x386/share/gsoap/import/ -I /home/qinyisong/gsoap_x386/share/gsoap/custom/
-c是產生純C代碼,如果提示找不到typemap.dat,將gsoap/下的typemap.dat複製到當前目錄就可以了。通過上列命令我們會得到如下文件: soapH.h soapC.c soap.nsmap soapClient.c soapServer.c soapClientLib.c soapServerLib. soapStub.h
soapH.h soap.c中函數及數據聲明,同時包含stdsoap.h頭文件,客戶端和服務器都會用到。
soapC.c 客戶端和服務器都會用到,soap通信協議的解析和編碼函數,使用soapH.h,其實核心文件。
soap.nsmap xsi、xsd等命名空間
soapClient.c 客戶端使用, 有關於遠程調用服務器功能的函數實現
soapServer.c 服務器使用,有關於服務器被調用實現函數
soapClientLib.c soapServerLib 用來生成更上層的client和server的封裝庫,無用
soapStub.h 服務器和客戶端都用,根據用戶頭文件生成的soap通信協議數據結構定義以及soap操作服務和客戶端的函數。
stdsoap2.h soap的基礎函數頭文件
stdsoap2.c soap的基礎函數比如soap初始化,soap的結構體堆分配以及各種設置函數等等
stdsoap2.c stdsoap2.h 必須拷貝到文件夾,不用生成,此文件實現soap的通信基礎函數和數據類型,是實現soap的底層網絡通信http等函數,與onvif.h無關
先大概記住他們的名字,將來會提到他們。
4、添加服務端代碼,創建文件:addserver.c
#include "soapH.h"
#include "soap.nsmap"
int main(int argc,char **argv)
{
int m,s;
struct soap add_soap;
soap_init(&add_soap);
soap_set_namespaces(&add_soap,namespaces);
if (argc<2)
{
printf("usage:%s<server_port>\n",argv[0]);
exit(1);
}
else
{
m=soap_bind(&add_soap,NULL,atoi(argv[1]),100);
if(m<0)
{
soap_print_fault(&add_soap,stderr);
exit(-1);
}
fprintf(stderr,"Socketconnectionsuccessful:mastersocket=%d\n",m);
for(;;)
{
s=soap_accept(&add_soap);
if (s<0)
{
soap_print_fault(&add_soap,stderr);
exit(-1);
}
fprintf(stderr,"Socketconnectionsuccessful:slavesocket=%d\n",s);
soap_serve(&add_soap);
soap_end(&add_soap);
}
}
return 0;
}
#if 1
int ns2_add(struct soap *add_soap,int num1,int num2,int *sum)
{
*sum=num1+num2;
return 0;
}
#endif
#include "soapStub.h"
#include "soap.nsmap"
int add(const char *server,int num1,int num2,int *sum)
{
struct soap add_soap;
int result=0;
soap_init(&add_soap);
soap_set_namespaces(&add_soap,namespaces);
soap_call_ns2_add(&add_soap,server,NULL,num1,num2,sum);
printf("serveris%s,num1is%d,num2is%d/n",server,num1,num2);
if (add_soap.error)
{
printf("soaperror:%d,%s,%s\n",add_soap.error,*soap_faultcode(&add_soap),*soap_faultstring(&add_soap));
result=add_soap.error;
}
soap_end(&add_soap);
soap_done(&add_soap);
return result;
}
6、寫客戶端測試代碼,創建文件:client_test.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int add(const char *server,int num1,int num2,int *sum);
int main(int argc,char **argv)
{
int result=-1;
char server[128]={0};
int num1;
int num2;
int sum;
if(argc<4)
{
printf("usage:%s<ip:port>num1num2\n",argv[0]);
exit(1);
}
strcpy(server,argv[1]);
num1=atoi(argv[2]);
num2=atoi(argv[3]);
result=add(server,num1,num2,&sum);
if(result!=0)
{
printf("soaperror,errcode=%d\n",result);
}
else
{
printf("%d+%d=%d\n",num1,num2,sum);
}
return 0;
}
7、編寫Makefile,編譯前,先將gsoap-2.8\gsoap目錄下的stdsoap2.c和stdsoap2.h複製到當前目錄下,它提供了對SOAP協議的簡單調用。
GSOAP_ROOT = /home/qinyisong/gsoap_x386/share/gsoap
CC = gcc -g -DWITH_NONAMESPACES
INCLUDE = -I$(GSOAP_ROOT)
SERVER_OBJS = soapC.o stdsoap2.o soapServer.o addserver.o
CLIENT_OBJS = soapC.o stdsoap2.o soapClient.o addclient.o client_test.o
#make default
all:server
#make server
server:$(SERVER_OBJS)
$(CC) $(INCLUDE) -o addserver $(SERVER_OBJS)
#make client
client:$(CLIENT_OBJS)
$(CC) $(INCLUDE) -o client_test $(CLIENT_OBJS)
clean:
rm -f *.o client_test
9、測試
一個最簡單的soap調用的例子完成了。
實例分析
服務端代碼
下面我們來分析上面的例子,剛纔我們只是創建一個add.h頭文件,在add.h頭文件中聲明瞭一個函數:
- int ns2__add( int num1, int num2, int* sum );
但是它好像多了一個struct soap類型的參數,這是soap全局運行環境,所有的函數都第一個包含這個參數。注意上面的Makefile,不管是編譯server還是編譯client都是沒有用到剛纔的add.h文件的。ns2__add真正的聲明在自動產生的soapStub.h中
然後在自動產生的soapServer.c中被soap_serve_ns2__add()函數調用。這樣,就將真正的加法運算的ns2__add函數和soap代碼框架聯繫了起來。那麼,在客戶端的代碼中又是怎樣來調用這個遠程函數的呢?
客戶端代碼
在剛纔添加的addtest.c中main函數中調用一個簡單的add函數
這個函數的實現也是我們自己添加的,在addclient.c中:
這個函數有些複雜,因爲它把客戶端的調用和soap聯繫了起來,還記得嗎,我們編譯server和client的時候複製了兩個文件stdsoap2.h和stdsoap2.c,這裏面的soap_init() soap_end()等函數來自他們。stdsoap2提供了soap協議的簡單操作,之需要簡單的函數調用就能完成遠程的函數調用。注意soap_call_ns2__add(),它同樣在soapStub.h中聲明,只不過是Client-Side Call Stubs,不明白stub意思的可以搜索rpc
這個函數的實現在自動產生的soapClient.c源文件中。同樣不需要我們實現。
這樣就可以通過調用gSOAP提供的stdsoap2的soap_init和自動產生的soap_call_ns2__add就實現了遠程主機上的ns2__add函數的調用