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(?
?num1,?
?num2,0)">*
?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


?main(
?argc,255)">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[]),?100);
 ?????????(m?)
 ????????{
 ????????????soap_print_fault( ????????????exit(-);
 ????????}
 ????????
 ????????fprintf(stderr,0)">Socket?connection?successful:?master?socket?=?%d/n ????????for?(?;?;?)
 ????????{?
 ????????????s??soap_accept(add_soap);?
 ?????????????(s?)
 ????????????{?
 ????????????????soap_print_fault( ????????????????exit();
 ????????????}
 ????????????fprintf(stderr,0)">Socket?connection?successful:?slave?socket?=?%d/n ????????????
 ????????????soap_serve(add_soap);该句说明该server的服务????????????soap_end(add_soap);
 ????????}
 ????}return;
 }

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

{
 ????*sum??num1?+?num2;
 ????

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



?add(
const
?server,0)">sum);


**
argv)?

?result?;
 ????char?serverhttp://localhost:4567?num2??sum?(?argc?3?)
 ????usage:?%s?num1?num2?/n
 ????
 ????num1??atoi(argv[]);
 ????num2?]);
 ????
 ????result??add(server,?num1,?num2,0)">sum);
 ?????(result?!=)
 ????soap?err,errcode?=?%d/n ????}
 ????%d+%d=%d/n ????}?add(?
sum?)

?soap?add_soap;
 ????;
 ????soap_init(add_soap);
 ????soap_set_namespaces(&add_soap,?add_namespaces);
 ????
 ????该函数是客户端调用的主要函数,后面几个参数和add.h中声明的一样,前面多了3个参数,函数名是接口函数名ns__add前面加上soap_call_????soap_call_ns__add(?"" ????(add_soap.error)
 ????soap?error:%d,%s,%s/nsoap_faultcode(add_soap),0)">soap_faultstring(add_soap)?);
 ????????result??add_soap.error;
 ????}?
 ????soap_end(add_soap);
 ????soap_done(?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(?dealloc?C++?data???????soap_end(?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

http://127.0.0.1
:8089/calc.wsdl

:8089/cal

gsoap?ns?schema??namespace:????urn:calc
double
?a,0)">?b,0)">result);

?ns__sub(
?ns__mul(
?ns__div(
?ns__pow(
result);

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

 #include?
 #include??
calc.nsmap
 #include??


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


 pthread_mutex_t?queue_cs;????????????????????????
队列锁
pthread_cond_t??queue_cv;??????????????????????????
条件变量
SOAP_SOCKET?????queue[MAX_QUEUE];???
数组队列
???????????????????????????head?
=
0
;??????????
队列头队列尾初始化?????????

//


 //
 void
??????process_queue(
);????????
线程入口函数
?????????enqueue(SOAP_SOCKET);??
入队列函数
SOAP_SOCKET?dequeue(
);?????????
出队列函数

?process_queue(
?soap)

{
 ???soap??tsoap??()soap;
 ??(;;)
 ??{
 ????????tsoap->socket??dequeue();
 ????????!soap_valid_socket(tsoapsocket))
 ???????{
 ?????????break;
 ????????}
 ????????soap_serve(tsoap);
 ????????soap_destroy(tsoap);
 ????????soap_end(tsoap);
 ??}
 ???NULL;
 }
入队列操作
?enqueue(SOAP_SOCKET?sock)

?status??SOAP_OK;
 ???next;
 ??pthread_mutex_lock(queue_cs);
 ??next??tail?;
 ???(next?>=?MAX_QUEUE)?
 ????next?==?head)?
 ??????status??SOAP_EOM;
 ??
 ??{
 ????queue[tail]?sock;
 ????tail??next;
 ??}
 ??pthread_cond_signal(queue_cv);
 ??pthread_mutex_unlock(queue_cs);
 ???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++];
 ???MAX_QUEUE)
 ????????{
 ????head?;
 ??}
 ??pthread_mutex_unlock(?sock;
 }



//////////////////////////具体服务方法////////////////////////////////////////
 加法的实现
soap,0)">result)

{
 ??????result??a??b;
 ???????SOAP_OK;
 }
?

减法的实现
result)

{?
 ??????b;
 ?????乘法的实现
result)

除法的实现
result)

{?
 ????(b)
 ???????/?b;
 ???
 ??s?)soap_malloc(soap,0)">1024);
 ?????????sprintf(s,0)">Can't>http:tempuri.org/">Can't?divide?%f?by?%f",?a,?b);??????????soap_sender_fault(soap,0)">Division?by?zero ??}乘方的实现
result)

{?
 ???pow(a,?b);
 ???(soap_errno??EDOM)??soap_errno?和errorno类似,?但是和widnows兼容?
 ??{?
 ????);
 ????sprintf(s,0)">Can't?take?the?power?of?%f?to??%f ????sprintf(s,0)">tempuri.org/">Can't?take?power?of?%f?to?%f",0)">????Power?function?domain?error?


//////////////////////////////////////////////////////////////////////////////////////////////////////
 主函数
?argv)

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

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