From: http://www.cppblog.com/qiujian5628/archive/2008/06/19/54019.html
完整源码下载
最近换了个工作环境,现在在大望路这边上班,呵,刚上班接到的任务就是熟悉gsoap!废话少说,现在开始gSoap学习!
gSOAP是一个夸平台的,用于开发Web Service服务端和客户端的工具,在Windows、Linux、MAC OS和UNIX下使用C和C++语言编码,集合了SSL功能。
下载地址:http://www.voidcn.com/tag/http://sourceforge.net/projects/gsoap2
官方网站:http://www.voidcn.com/tag/http://genivia.com/Products/gsoap/index.html
对于Windows平台下开发客户端,首先下载最新的gsoap_win32_2.7.6c.zip包,具体在以下地址:http://optusnet.dl.sourceforge.net/sourceforge/gsoap2/gsoap_win32_2.7.6c.zip 首先查看gsoap的User's Guide,基本就能对gsoap有个全面的了解,通过阅读Sample里的例子程序深入。然后搜索网上其它一些文章,比如:
gSOAP简单多线程服务器程序
http://blog.chinaunix.net/u1/55091/showart_430965.html
纯c gSoap实现WebService???????????
http://hi.baidu.com/2sky2sea/blog/item/40ec5555680279c1b745ae9b.html?
接下来我结合自己的实践与理解,讲讲VC用gsoap下编写webService和客户端程序,有不对的地方还请大家指正,谢谢。
我以网上出现的实现一个简单的加法函数为例,讲讲我在操作过程中遇到的问题。
一 服务器端
1.首先编写 add.h文件:
1
 //
gsoap?ns?service?name:?add
2

//
gsoap?ns?service?namespace:?
http://localhost/add.wsdl
3

//
gsoap?ns?service?location:?
http://localhost
4

//
gsoap?ns?service?executable:?add.cgi
5

//
gsoap?ns?service?encoding:?encoded
6

//
gsoap?ns?schema?namespace:?urn:add
7

8

int
?ns__add(?
int
?num1,?
int
?num2,?
int
*
?sum?);
9

2.用gsoap/bin目录下的soapcpp2.exe程序,生成一些文件。可以把soapcpp2.exe拷贝到一add.h目录下,用cmd执行soapcpp2.exe add.h就可以,在这个目录下会自动生成许多将来有用的文件,如add.namap,soapH.h,soapC.cpp,soapClient.cpp,soapServer.cpp等文件。soapcpp2.exe可以带参数执行,具体执行soapcpp2.exe -h查看。
3.新建一个win32控制台工程,加入wsock32.lib库,将刚才生成的那些文件添加到工程中。然后编写webserver.cpp主程序:
 #include?
"
add.h
"
 #include?
"
add.nsmap
"


int
?main(
int
?argc,?
char
*
?argv[])

{
 ????
 ????int?m,?s;?/*?master?and?slave?sockets?*/
 ????struct?soap?add_soap;
 ????soap_init(&add_soap);
 ????//soap_set_namespaces(&add_soap,?add_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,?"Socket?connection?successful:?master?socket?=?%dn",?m);
 ????????for?(?;?;?)
 ????????{?
 ????????????s?=?soap_accept(&add_soap);?
 ????????????if?(s?<?0)
 ????????????{?
 ????????????????soap_print_fault(&add_soap,?stderr);
 ????????????????exit(-1);
 ????????????}
 ????????????fprintf(stderr,?"Socket?connection?successful:?slave?socket?=?%dn",?s);
 ????????????
 ????????????soap_serve(&add_soap);//该句说明该server的服务
 ????????????soap_end(&add_soap);
 ????????}
 ????}
 ????return?0;
 }

//
server端的实现函数与add.h中声明的函数相同,但是多了一个当前的soap连接的参数

int
?ns__add(
struct
?soap?
*
add_soap,?
int
?num1,?
int
?
*
sum)

{
 ????*sum?=?num1?+?num2;
 ????return?0;
 }

4. 编译这个程序,会提示错误,将gsoap_win32目录下stdsoap2.cpp,stdsoap2.h文件加入工程,重新编译如果还有错误,可能是你将add.h生成的文件添加入工程出错的原因。实际上在编写server程序时,无须带Client的那些文件,还有带Lib的文件也无须添加到工程中。再重新编译应该就没有问题了,启动4567端口,在ie中输入localhost:4567,如果显示xml页面,说明程序已经启动。
二 对应的客户端
1。客户端程序代码如下:
 #include?
<
stdio.h
>
 #include?
<
stdlib.h
>
 #include?
"
soapH.h
"
 #include?
"
add.nsmap
"



int
?add(
const
?
char
*
?server,?
int
?
*
sum);


int
?main(
int
?argc,?
char
?
**
argv)?

{
 ????int?result?=?-1;
 ????char*?server="http://localhost:4567";
 ????int?num1?=?0;
 ????int?num2?=?0;
 ????int?sum?=?0;
 ????if(?argc?<?3?)
 ????{
 ????????printf("usage:?%s?num1?num2?n",?argv[0]);
 ????????exit(0);
 ????}
 ????
 ????num1?=?atoi(argv[1]);
 ????num2?=?atoi(argv[2]);
 ????
 ????result?=?add(server,?num1,?num2,?&sum);
 ????if?(result?!=?0)
 ????{
 ????????printf("soap?err,errcode?=?%dn",?result);
 ????}
 ????else
 ????{
 ????????printf("%d+%d=%dn",?sum?);
 ????}
 ????return?0;
 }


int
?add(?
const
?
char
*
?server,?
int
?
*
sum?)

{
 ????struct?soap?add_soap;
 ????int?result?=?0;
 ????soap_init(&add_soap);
 //????soap_set_namespaces(&add_soap,?add_namespaces);
 ????
 ????//该函数是客户端调用的主要函数,后面几个参数和add.h中声明的一样,前面多了3个参数,函数名是接口函数名ns__add前面加上soap_call_
 ????soap_call_ns__add(?&add_soap,?server,?"",?sum?);
 ????if(add_soap.error)
 ????{
 ????????printf("soap?error:%d,%s,%sn",?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;
 }
2.客户端程序既可以新建一个新的win32控制台程序,将刚才生成的nsmap,soapClient.h等文件加入工程,编译既可。我是直接在原先工程中加入一客户端代码,将webserver.cpp文件移除,并且将soapServer.cpp等server端需要的文件移除,将soapClient.cpp等client端需要的cpp添加到工程,编译既可。
3.启动server程序,F5客户端程序,经测试正常。
三 遇到的问题
1.server端可以编译成CGI方式执行,而并不是绑定到某个端口,这种方式我没有实践。
 if
?(argc?
<
?
2
)?
//
?no?args:?assume?this?is?a?CGI?application?

???
{?
 ??????soap_serve(&soap);?//?serve?request,?one?thread,?CGI?style?
 ??????soap_destroy(&soap);?//?dealloc?C++?data?
 ??????soap_end(&soap);?//?dealloc?data?and?clean?up?
 }
2.在编译服务器及客户端程序时一开始对add.h生成的文件添加到工程,经常出现问题,需要自己不调试。特别是链接时段,server/client要与其生成的文件相对应,server调用生成的soapserver.cpp,client调用生成的soapclient.cpp文件。
3.多线程方式,在windows下建议用pthread_win32库,这里给出多线程下的例子。
 一?gSOAP需要的头文件:


//
gsoap?ns?service?name:?calc

//
gsoap?ns?service?style:?rpc

//
gsoap?ns?service?encoding:?encoded

//
gsoap?ns?service?namespace:?
http://127.0.0.1
:8089/calc.wsdl

//
gsoap?ns?service?location:?
http://127.0.0.1
:8089/cal

//
gsoap?ns?schema??namespace:????urn:calc

int
?ns__add(
double
?a,?
double
?b,?
double
?
*
result);

int
?ns__sub(
double
?a,?
double
?
*
result);

int
?ns__mul(
double
?a,?
double
?
*
result);

int
?ns__div(
double
?a,?
double
?
*
result);

int
?ns__pow(
double
?a,?
double
?
*
result);

 二?多线程服务器关键代码

 #include?
 #include??
"
calc.nsmap
"
 #include??
"
soapH.h
"


/////////////////////////////////////////////////////////////////////////
 ///宏与全局变量的定义
 #define
??BACKLOG?(100)??

#define
??MAX_THR?(10)???

#define
??MAX_QUEUE?(1000)


 pthread_mutex_t?queue_cs;????????????????????????
//
队列锁

pthread_cond_t??queue_cv;??????????????????????????
//
条件变量

SOAP_SOCKET?????queue[MAX_QUEUE];???
//
数组队列

int
???????????????????????????head?
=
0
,?tail?
=
0
;??????????
//
队列头队列尾初始化?????????

//////////////////////////////////////////////////////////////////////////


 //////////////////////////////////////////////////////////////////////////
 void
?
*
??????process_queue(
void
?
*
);????????
//
线程入口函数

int
?????????enqueue(SOAP_SOCKET);??
//
入队列函数

SOAP_SOCKET?dequeue(
void
);?????????
//
出队列函数


//////////////////////////////////////////////////////////////////////////
 //
线程入口函数

void
?
*
?process_queue(
void
?
*
?soap)

{
 ??struct?soap?*?tsoap?=?(struct?soap?*)soap;
 ??for(;;)
 ??{
 ????????tsoap->socket?=?dequeue();
 ????????if?(!soap_valid_socket(tsoap->socket))
 ???????{
 ?????????break;
 ????????}
 ????????soap_serve(tsoap);
 ????????soap_destroy(tsoap);
 ????????soap_end(tsoap);
 ??}
 ??return?NULL;
 }


//
入队列操作

int
?enqueue(SOAP_SOCKET?sock)

{
 ??int?status?=?SOAP_OK;
 ??int?next;
 ??pthread_mutex_lock(&queue_cs);
 ??next?=?tail?+1;
 ??if?(next?>=?MAX_QUEUE)?
 ????next?=?0;
 ??if?(next?==?head)?
 ??????status?=?SOAP_EOM;
 ??else
 ??{
 ????queue[tail]?=sock;
 ????tail?=?next;
 ??}
 ??pthread_cond_signal(&queue_cv);
 ??pthread_mutex_unlock(&queue_cs);
 ??return?status;
 }


//
出队列操作

SOAP_SOCKET?dequeue()

{
 ??SOAP_SOCKET?sock;
 ??pthread_mutex_lock(&queue_cs);
 ???while?(head?==?tail?)
 ???{
 ??????????pthread_cond_wait(&queue_cv,&queue_cs);
 ???}
 ??sock?=?queue[head++];
 ??if?(head?>=?MAX_QUEUE)
 ????????{
 ????head?=0;
 ??}
 ??pthread_mutex_unlock(&queue_cs);
 ??return?sock;
 }



//////////////////////////具体服务方法////////////////////////////////////////
 //
加法的实现

int
?ns__add(
struct
?soap?
*
soap,?
double
?a,?
double
?
*
result)

{
 ??????*result?=?a?+?b;
 ??????return?SOAP_OK;
 }
?

//
减法的实现

int
?ns__sub(
struct
?soap?
*
soap,?
double
?
*
result)

{?
 ?????*result?=?a?-?b;
 ?????return?SOAP_OK;
 }
?

//
乘法的实现

int
?ns__mul(
struct
?soap?
*
soap,?
double
?
*
result)

{?
 ?????*result?=?a?*?b;
 ?????return?SOAP_OK;
 }
?

//
除法的实现

int
?ns__div(
struct
?soap?
*
soap,?
double
?
*
result)

{?
 ???if?(b)
 ???????*result?=?a?/?b;
 ???else
 ??{
 ?????????char?*s?=?(char*)soap_malloc(soap,?1024);
 ?????????sprintf(s,?"Can't">http://tempuri.org/">Can't?divide?%f?by?%f",?a,?b);
 ?????????return?soap_sender_fault(soap,?"Division?by?zero",?s);
 ??}
 ??return?SOAP_OK;
 }
?

//
乘方的实现

int
?ns__pow(
struct
?soap?
*
soap,?
double
?
*
result)

{?
 ??*result?=?pow(a,?b);
 ??if?(soap_errno?==?EDOM)?/*?soap_errno?和errorno类似,?但是和widnows兼容?*/
 ??{?
 ????char?*s?=?(char*)soap_malloc(soap,?1024);
 ????sprintf(s,?"Can't?take?the?power?of?%f?to??%f",?b);
 ????sprintf(s,?"Can't">http://tempuri.org/">Can't?take?power?of?%f?to?%f",?b);
 ????return?soap_sender_fault(soap,?"Power?function?domain?error",?s);
 ??}
 ??return?SOAP_OK;
 }
?


//////////////////////////////////////////////////////////////////////////////////////////////////////
 //
主函数

int
?main(
int
?argc,
char
?
**
?argv)

{
 ??struct?soap?ServerSoap;
 ?????//初始话运行时环境
 ????soap_init(&ServerSoap);
 ????//如果没有参数,当作CGI程序处理
 ????if?(argc?<2)?
 ????{???????
 ???????????//CGI?风格服务请求,单线程
 ??????????soap_serve(&ServerSoap);
 ??????????//清除序列化的类的实例
 ?????????soap_destroy(&ServerSoap);
 ?????????//清除序列化的数据
 ????????soap_end(&ServerSoap);?????
 ???}else
 ???{
 ?????struct?soap?*?soap_thr[MAX_THR];
 ?????pthread_t?tid[MAX_THR];
 ?????int?i,port?=?atoi(argv[1]);
 ?????SOAP_SOCKET?m,s;
 ??????//锁和条件变量初始化
 ?????pthread_mutex_init(&queue_cs,NULL);
 ?????pthread_cond_init(&queue_cv,NULL);
 ?????//绑定服务端口
 ????m?=?soap_bind(&ServerSoap,NULL,port,BACKLOG);
 ????//循环直至服务套接字合法
 ????while?(!soap_valid_socket(m))
 ???{
 ????????????????fprintf(stderr,"Bind?port?error!?");
 ????????????????m?=?soap_bind(&ServerSoap,BACKLOG);
 ????}
 ????fprintf(stderr,"socket?connection?successful?%d?",m);
 ????????????????
 ?????//生成服务线程
 ????for(i?=?0;?i?<MAX_THR;?i++)

 ???{
 ??????soap_thr[i]?=?soap_copy(&ServerSoap);
 ??????fprintf(stderr,"Starting?thread?%d?",i);
 ??????pthread_create(&tid[i],(void*(*)(void*))process_queue,(void*)soap_thr[i]);
 ????}
 ????????????????
 ????for(;;)
 ????{
 ??????//接受客户端的连接
 ??????s?=?soap_accept(&ServerSoap);
 ??????if?(!soap_valid_socket(s))?
 ??????{
 ????????if?(ServerSoap.errnum)?
 ????????????????????????????????{
 ??????????soap_print_fault(&ServerSoap,stderr);
 ??????????continue;
 ????????}else
 ????????{
 ??????????fprintf(stderr,"Server?timed?out?");
 ??????????break;
 ????????}
 ??????}
 ???????//客户端的IP地址
 ??????fprintf(stderr,"Accepted?connection?from?IP=?%d.%d.%d.%d?socket?=?%d?",
 ???????????????????????????????((ServerSoap.ip)>>24)&0xFF,((ServerSoap.ip)>>16)&0xFF,((ServerSoap.ip)>>8)&0xFF,(ServerSoap.ip)&0xFF,(ServerSoap.socket));
 ??????//请求的套接字进入队列,如果队列已满则循环等待
 ???????while(enqueue(s)?==?SOAP_EOM)
 ????????????????Sleep(1000);
 ????}
 ????//服务结束后的清理工作
 ????for(i?=?0;?i?<?MAX_THR;?i++)
 ????{
 ??????while?(enqueue(SOAP_INVALID_SOCKET)?==?SOAP_EOM)?
 ???????{
 ???????????Sleep(1000);
 ??????}
 ????}
 ????for(i=0;?i<?MAX_THR;?i++)
 ????{
 ??????fprintf(stderr,"Waiting?for?thread?%d?to?terminate?..",i);
 ??????pthread_join(tid[i],NULL);
 ??????fprintf(stderr,"terminated?");
 ??????soap_done(soap_thr[i]);
 ??????free(soap_thr[i]);
 ????}
 ????pthread_mutex_destroy(&queue_cs);
 ????pthread_cond_destroy(&queue_cv);
 ??}
 ????//分离运行时的环境
 ??soap_done(&ServerSoap);
 ??return?0;
 }
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|