Chinaunix首页 | 论坛 | 博客
  • 博客访问: 400131
  • 博文数量: 158
  • 博客积分: 1227
  • 博客等级: 少尉
  • 技术积分: 946
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-20 16:19
文章分类
文章存档

2016年(1)

2015年(1)

2012年(107)

2011年(49)

分类:

2011-06-03 17:25:24

由于有认证的免费资源实在难找,我只好把公司正在使用的一个服务的 wsdl 裁剪一下,拿到这里作为实例,裁剪后的 wsdl 只保留一个 echo 接口,顾名思义,就是客户端送什么字符串上来,服务端就返回同样的字符串。这个 wsdl 如下(业务相关的网址和 end point 均已作了特别处理):

 

  1. xml version='1.0' encoding='UTF-8'?>  
  2. <s0:definitions name="ServicesDefinitions" targetNamespace="http://echo.rsecure.com/ECHO" xmlns="" xmlns:s0="" xmlns:s1="http://echo.rsecure.com/ECHO" xmlns:s2="soap/">  
  3.   <s0:types>  
  4.     <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://echo.rsecure.com/ECHO" xmlns:s0="" xmlns:s1="http://echo.rsecure.com/ECHO" xmlns:s2="soap/" xmlns:xs="">  
  5.       <xs:element name="echo">  
  6.         <xs:complexType>  
  7.           <xs:sequence>  
  8.             <xs:element name="EchoMessage" type="xs:string"/>  
  9.           xs:sequence>  
  10.         xs:complexType>  
  11.       xs:element>  
  12.       <xs:element name="echoResponse">  
  13.         <xs:complexType>  
  14.           <xs:sequence>  
  15.             <xs:element name="Echo" type="xs:string"/>  
  16.           xs:sequence>  
  17.         xs:complexType>  
  18.       xs:element>  
  19.     xs:schema>  
  20.   s0:types>  
  21.   <s0:message name="echo">  
  22.     <s0:part element="s1:echo" name="parameters"/>  
  23.   s0:message>  
  24.   <s0:message name="echoResponse">  
  25.     <s0:part element="s1:echoResponse" name="Echo"/>  
  26.   s0:message>  
  27.   <s0:portType name="LMIAPort">  
  28.     <s0:operation name="echo" parameterOrder="parameters">  
  29.       <s0:input message="s1:echo"/>  
  30.       <s0:output message="s1:echoResponse"/>  
  31.     s0:operation>  
  32.   s0:portType>  
  33.   <s0:binding name="ServicesSoapBinding" type="s1:LMIAPort">  
  34.     <s2:binding style="document" mce_style="document" transport=""/>  
  35.     <s0:operation name="echo">  
  36.       <s2:operation style="document" mce_style="document"/>  
  37.       <s0:input>  
  38.         <s2:body parts="parameters" use="literal"/>  
  39.       s0:input>  
  40.       <s0:output>  
  41.         <s2:body parts="Echo" use="literal"/>  
  42.       s0:output>  
  43.     s0:operation>  
  44.   s0:binding>  
  45.   <s0:service name="Services">  
  46.     <s0:port binding="s1:ServicesSoapBinding" name="lmiAPort">  
  47.       <s2:address location=""/>  
  48.     s0:port>  
  49.   s0:service>  
  50. s0:definitions>  

 

gsoap-2.7/gsoap/wsdl/ 目录下建立两个目录: echo echo_server ,按照前几节的方法分别建立 gSOAP 客户端和服务端。客户端与前几节的相比,首先是增加了 soap­_ssl_client_context 处理 HTTPS 协议。其次,本案例使用的是基本认证 (Basic Authentication) ,需要在 soap 变量初始化之后给出用户名和密码。

        struct soap soap;

        soap_init(&soap);

        soap.userid = argv[1];

        soap.passwd = argv[2];

 

客户端完整程序如下:

 

  1. #include "soapH.h"  
  2. #include "ServicesSoapBinding.nsmap"  
  3. int main(int argc, char **argv) {  
  4.     if ( argc != 4 && argc != 5 ) {  
  5.         printf("Usage: %s username password message [end_point]\n", argv[0]);  
  6.         exit(-1);  
  7.     }  
  8.     struct soap soap;  
  9.     soap_init(&soap);  
  10.     soap.userid = argv[1];  
  11.     soap.passwd = argv[2];  
  12.     struct _ns1__echo request;  
  13.     struct _ns1__echoResponse response;  
  14.     soap_ssl_init();  
  15.     if ( soap_ssl_client_context(&soap, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL) ) {  
  16.         soap_print_fault(&soap, stderr);  
  17.         exit(-1);  
  18.     }  
  19.     request.EchoMessage = argv[3];  
  20.     char *endpoint = NULL;  
  21.     if ( argc == 5 )  
  22.         endpoint = argv[4];  
  23.     printf("username  : %s\n", soap.userid);  
  24.     printf("password  : %s\n", soap.passwd);  
  25.     printf("message   : %s\n", request.EchoMessage);  
  26.     if ( endpoint )  
  27.         printf("end point : %s\n", endpoint);  
  28.     if ( soap_call___ns1__echo(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {  
  29.         printf("%s\n", response.Echo);  
  30.     }  
  31.     else {  
  32.         soap_print_fault(&soap, stderr);  
  33.     }  
  34.     soap_destroy(&soap);  
  35.     soap_end(&soap);  
  36.     soap_done(&soap);  
  37.     return 0;  
  38. }  

 

保存为 echo.c ,编译命令如下,注意增加了 -DWITH_OPENSSL 参数,以及需要链接 libssl 库。

gcc -DWITH_OPENSSL -O2 -o echo echo.c soapC.c soapClient.c ../../stdsoap2.c -I../.. -L../.. -lgsoap –lssl

 

服务端的编写相对麻烦,以下给出一个最简单的实现。与第二节的 stock 服务端程序相比,主要是增加了 soap_ssl_server_context 处理 HTTPS 协议,其中需要用到 gsoap-2.7.17 自带的 ssl 实例程序中的几个 pem 证书,把它们拷贝过来即可使用。另外,与不需要认证的应用相比, __ns1__echo 增加了用户密码校验。这个案例里,设定客户端送上来的用户 / 密码应当为 roy/liang ,否则将返回 401 错误。

 

  1. #include   
  2. #include "soapH.h"  
  3. #include "ServicesSoapBinding.nsmap"  
  4. void *process_request(void *soap) {  
  5.     pthread_detach(pthread_self());  
  6.     if ( soap_ssl_accept((struct soap *) soap) != SOAP_OK )  
  7.         soap_print_fault((struct soap *) soap, stderr);  
  8.     else  
  9.         soap_serve((struct soap *) soap);  
  10.     soap_end((struct soap *) soap);  
  11.     soap_free((struct soap *) soap);  
  12.     return NULL;  
  13. }  
  14. int main(int argc, char **argv) {  
  15.     if ( argc != 2 ) {  
  16.         printf("Usage: %s port\n", argv[0]);  
  17.         exit(-1);  
  18.     }  
  19.     int port = atol(argv[1]);  
  20.     pthread_t tid;  
  21.     struct soap *tsoap;  
  22.     struct soap soap;  
  23.     soap_init(&soap);  
  24.     soap_ssl_init();  
  25.     if ( soap_ssl_server_context(&soap, SOAP_SSL_DEFAULT, "server.pem""password""cacert.pem", NULL, "dh512.pem", NULL, argv[0]) ) {  
  26.         soap_print_fault(&soap, stderr);  
  27.         exit(-1);  
  28.     }  
  29.     int m, s;  
  30.     if ( (m = soap_bind(&soap, NULL, port, 100)) < 0 ) {  
  31.         soap_print_fault(&soap, stderr);  
  32.     }  
  33.     else {  
  34.         printf("Socket connect successfully: master socket = %d\n", m);  
  35.         int i = 0;  
  36.         while ( 1 ) {  
  37.             if ( (s = soap_accept(&soap)) < 0 ) {  
  38.                 soap_print_fault(&soap, stderr);  
  39.                 break;  
  40.             }  
  41.             printf("Connection %d accepted from IP = %d.%d.%d.%d, slave socket = %d\n", ++i, (soap.ip >> 24) & 0xff, (soap.ip >> 16) & 0xff, (soap.ip >> 8) & 0xff, soap.ip & 0xff, s);  
  42.             tsoap = soap_copy(&soap);  
  43.             if ( !tsoap ) {  
  44.                 soap_closesock(&soap);  
  45.                 continue;  
  46.             }  
  47.             pthread_create(&tid, NULL, &process_request, (void *) tsoap);  
  48.         }  
  49.     }  
  50.     soap_done(&soap);  
  51.     return 0;  
  52. }  
  53. int __ns1__echo(  
  54.     struct soap *soap,  
  55.     struct _ns1__echo *request,  
  56.     struct _ns1__echoResponse *response) {  
  57.     if ( !soap->userid || !soap->passwd || strcmp(soap->userid, "roy") || strcmp(soap->passwd, "liang") )  
  58.         return 401;  
  59.     int len = strlen(request->EchoMessage);  
  60.     response->Echo = (char *) malloc(sizeof(char) * (len + 1));  
  61.     strcpy(response->Echo, request->EchoMessage);  
  62.     return SOAP_OK;  
  63. }  


 

保存为 echo_server.c ,编译命令是:

gcc -DWITH_OPENSSL -O2 -o echo_server echo_server.c soapC.c soapServer.c ../../stdsoap2.c -I../.. -L../.. -lgsoap -lssl -lcrypto –lpthread

 

客户端和服务端都编译完成后,首先启动服务端:

-bash-3.2$ ./echo_server 6883

Socket connect successfully: master socket = 3

 

然后,在另一个窗口运行客户端,由于 wsdl 里已经指定默认 end point ,因此,客户端并不需要额外给出。

 

正常的返回结果:

-bash-3.2$ ./echo roy liang hi

username  : roy

password  : liang

message   : hi

hi

 

用户、密码不正确将返回 401 错误:

-bash-3.2$ ./echo roy xxx hi

username  : roy

password  : xxx

message   : hi

Error 401 fault: SOAP-ENV:Server [no subcode]

"HTTP/1.1 401 Unauthorized"

Detail:

SOAP-ENV:ClientHTTP Error: 401 Unauthorized

 

基于 HTTP 的基本认证 (Basic Authentication) 比基于 HTTPS 的更加简单,在客户端和服务端的程序去除 HTTPS 处理即可,不再赘述。

 

另外,本案例中用到的证书的失效日期好像是 2010 11 2 日,在此之后执行的结果可能会不一样。

阅读(1499) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~