http://blog.csdn.net/yui/article/details/5747433
电信provisioning系统中,常常需要与远程服务器实时交换一些数据,以完成用户的请求。由于简单对象访问协议(Simple Object Access Protocol, SOAP)的流行,许多涉及到第三方的应用,我们一般都比较乐意使用SOAP来开发。不过,由于可能涉及到公司的机密,本系列教程的开发实例尽量采用在网上已经公开的Web Service资源。
上文已经交待了gSOAP在Linux环境下的编译方法和客户端的实例程序,本文继续讲解其服务端程序的开发。由于不可能获得真正的数据库内容,我们设定的目标是,所有返回的内容都是客户端传入的股票代码。
首先,在gsoap-2.7/gsoap/wsdl/下创建一个stock_server目录
-bash-3.2$ mkdir -p stock_server
改变当前路径为stock_server
-bash-3.2$ cd stock_server
仍然使用wsdl2h生成基于纯C代码的stock.h
-bash-3.2$ ../wsdl2h -c -o stock.h http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx?wsdl
然后,生成服务端存根程序,并且不生成xml文件和soapServerLib.c
-bash-3.2$ ../../bin/linux386/soapcpp2 -S -L -x stock.h
** The gSOAP code generator for C and C++, soapcpp2 release 2.7.17
** Copyright (C) 2000-2010, Robert van Engelen, Genivia Inc.
** All Rights Reserved. This product is provided "as is", without any warranty.
** The soapcpp2 tool is released under one of the following three licenses:
** GPL, the gSOAP public license, or the commercial license by Genivia Inc.
Saving soapStub.h annotated copy of the input declarations
Saving soapH.h interface declarations
Saving soapC.c XML serializers
Saving soapServer.c server request dispatcher
Using ns2 service name: ChinaStockWebServiceSoap
Using ns2 service style: document
Using ns2 service encoding: literal
Using ns2 service location: http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx
Using ns2 schema namespace: http://WebXml.com.cn/ChinaStockWebServiceSoap
Saving ChinaStockWebServiceSoap.nsmap namespace mapping table
Using ns3 service name: ChinaStockWebServiceSoap12
Using ns3 service style: document
Using ns3 service encoding: literal
Using ns3 service location: http://webservice.webxml.com.cn/WebServices/ChinaStockWebService.asmx
Using ns3 schema namespace: http://WebXml.com.cn/ChinaStockWebServiceSoap12
Saving ChinaStockWebServiceSoap12.nsmap namespace mapping table
Compilation successful
服务端的主程序稍微比客户端复杂些,因为还要处理客户端的其他请求,至少要有其函数体,否则编译时会报错。
- #include "soapH.h"
- #include "ChinaStockWebServiceSoap12.nsmap"
-
- int main(int argc, char **argv) {
- if ( argc != 2 ) {
- printf("Usage: %s port/n", argv[0]);
- exit(-1);
- }
- int port = atol(argv[1]);
-
- struct soap soap;
- soap_init(&soap);
- int m, s;
- if ( (m = soap_bind(&soap, NULL, port, 100)) < 0 ) {
- soap_print_fault(&soap, stderr);
- }
- else {
- printf("Socket connect successfully: master socket = %d/n", m);
- int i = 0;
- while ( 1 ) {
- if ( (s = soap_accept(&soap)) < 0 ) {
- soap_print_fault(&soap, stderr);
- break;
- }
- 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);
- if ( soap_serve(&soap) != SOAP_OK ) {
- soap_print_fault(&soap, stderr);
- break;
- }
- soap_end(&soap);
- }
- }
- soap_done(&soap);
- }
-
- int __ns3__getStockInfoByCode(
- struct soap *soap,
- struct _ns1__getStockInfoByCode *request,
- struct _ns1__getStockInfoByCodeResponse *response) {
- int element_counter = 25;
- response->getStockInfoByCodeResult = (struct ns1__ArrayOfString *) malloc(sizeof(struct ns1__ArrayOfString));
- response->getStockInfoByCodeResult->__sizestring = element_counter;
- response->getStockInfoByCodeResult->string = (char **) malloc(sizeof(char *) * element_counter);
- int i = 0;
- for ( i = 0; i < element_counter; i++ ) {
- response->getStockInfoByCodeResult->string[i] = (char *) malloc(sizeof(char) * 32);
- strcpy(response->getStockInfoByCodeResult->string[i], request->theStockCode);
- }
- return SOAP_OK;
- }
-
- int __ns3__getStockImage_USCOREkByteByCode(
- struct soap *soap,
- struct _ns1__getStockImage_USCOREkByteByCode *request,
- struct _ns1__getStockImage_USCOREkByteByCodeResponse *response) {
- return SOAP_OK;
- }
-
- int __ns3__getStockImage_USCOREkByCode(
- struct soap *soap,
- struct _ns1__getStockImage_USCOREkByCode *request,
- struct _ns1__getStockImage_USCOREkByCodeResponse *response) {
- return SOAP_OK;
- }
-
- int __ns3__getStockImageByteByCode(
- struct soap *soap,
- struct _ns1__getStockImageByteByCode *request,
- struct _ns1__getStockImageByteByCodeResponse *response) {
- return SOAP_OK;
- }
-
- int __ns3__getStockImageByCode(
- struct soap *soap,
- struct _ns1__getStockImageByCode *request,
- struct _ns1__getStockImageByCodeResponse *response) {
- return SOAP_OK;
- }
-
- int __ns2__getStockInfoByCode(
- struct soap *soap,
- struct _ns1__getStockInfoByCode *request,
- struct _ns1__getStockInfoByCodeResponse *response) {
- int element_counter = 25;
- response->getStockInfoByCodeResult = (struct ns1__ArrayOfString *) malloc(sizeof(struct ns1__ArrayOfString));
- response->getStockInfoByCodeResult->__sizestring = element_counter;
- response->getStockInfoByCodeResult->string = (char **) malloc(sizeof(char *) * element_counter);
- int i = 0;
- for ( i = 0; i < element_counter; i++ ) {
- response->getStockInfoByCodeResult->string[i] = (char *) malloc(sizeof(char) * 32);
- strcpy(response->getStockInfoByCodeResult->string[i], request->theStockCode);
- }
- return SOAP_OK;
- }
-
- int __ns2__getStockImage_USCOREkByteByCode(
- struct soap *soap,
- struct _ns1__getStockImage_USCOREkByteByCode *request,
- struct _ns1__getStockImage_USCOREkByteByCodeResponse *response) {
- return SOAP_OK;
- }
-
- int __ns2__getStockImage_USCOREkByCode(
- struct soap *soap,
- struct _ns1__getStockImage_USCOREkByCode *request,
- struct _ns1__getStockImage_USCOREkByCodeResponse *response) {
- return SOAP_OK;
- }
-
- int __ns2__getStockImageByteByCode(
- struct soap *soap,
- struct _ns1__getStockImageByteByCode *request,
- struct _ns1__getStockImageByteByCodeResponse *response) {
- return SOAP_OK;
- }
-
- int __ns2__getStockImageByCode(
- struct soap *soap,
- struct _ns1__getStockImageByCode *request,
- struct _ns1__getStockImageByCodeResponse *response) {
- return SOAP_OK;
- }
值得注意的是,如果项目中存在多个name space,最好把全部name space的相关方法都进行编码,否则可能出现意想不到的错误:客户端明明是调用ns3的方法,但是服务端却使用了ns2的方法来提供服务。这一点我也比较费解,可能与wsdl本身的写法有关。
上述服务端程序的编译命令是
gcc -O2 -o stock_server stock_server.c soapC.c soapServer.c ../../stdsoap2.c -I../.. -L../.. -lgsoap
同时,要把上文的客户端程序修改一下,支持指定的end point,不指定end point再取默认的end point
- #include "soapH.h"
- #include "ChinaStockWebServiceSoap12.nsmap"
-
- int main(int argc, char **argv) {
- if ( argc != 2 && argc != 3 ) {
- printf("Usage: %s stock_code [end_point]/n", argv[0]);
- exit(-1);
- }
-
- struct soap soap;
- soap_init(&soap);
- soap_set_mode(&soap, SOAP_C_UTFSTRING);
- struct _ns1__getStockInfoByCode request;
- struct _ns1__getStockInfoByCodeResponse response;
-
- request.theStockCode = argv[1];
- char *endpoint = NULL;
- if ( argc == 3 )
- endpoint = argv[2];
- if ( soap_call___ns3__getStockInfoByCode(&soap, endpoint, NULL, &request, &response) == SOAP_OK ) {
- int element_counter = response.getStockInfoByCodeResult->__sizestring;
- int i = 0;
- for ( i = 0; i < element_counter; i++ ) {
- switch ( i ) {
- case 0 : printf("Stock code : "); break;
- case 1 : printf("Stock name : "); break;
- case 2 : printf("Timestamp : "); break;
- case 3 : printf("Latest price : "); break;
- case 4 : printf("Closing price T-1 : "); break;
- case 5 : printf("Opening price : "); break;
- case 6 : printf("Ups and downs : "); break;
- case 7 : printf("Mininum price : "); break;
- case 8 : printf("Maxinum price : "); break;
- case 9 : printf("Amount of up/down : "); break;
- case 10 : printf("Trading volume : "); break;
- case 11 : printf("Trading amount : "); break;
- case 12 : printf("Buy price : "); break;
- case 13 : printf("Sell price : "); break;
- case 14 : printf("Agency trans : "); break;
- case 15 : printf("Buy 1 : "); break;
- case 16 : printf("Buy 2 : "); break;
- case 17 : printf("Buy 3 : "); break;
- case 18 : printf("Buy 4 : "); break;
- case 19 : printf("Buy 5 : "); break;
- case 20 : printf("Sell 1 : "); break;
- case 21 : printf("Sell 2 : "); break;
- case 22 : printf("Sell 3 : "); break;
- case 23 : printf("Sell 4 : "); break;
- case 24 : printf("Sell 5 : "); break;
- default : break;
- }
- printf("%s/n", response.getStockInfoByCodeResult->string[i]);
- }
- }
- else {
- soap_print_fault(&soap, stderr);
- }
-
- soap_destroy(&soap);
- soap_end(&soap);
- soap_done(&soap);
- return 0;
- }
使服务端程序在某一高位端口下运行,比如
-bash-3.2$ ./stock_server 6883
Socket connect successfully: master socket = 3
另起一个窗口执行客户端程序,并且指定end point
-bash-3.2$ ./stock sh600000 http://localhost:6883
Stock code : sh600000
Stock name : sh600000
Timestamp : sh600000
Latest price : sh600000
Closing price T-1 : sh600000
Opening price : sh600000
Ups and downs : sh600000
Mininum price : sh600000
Maxinum price : sh600000
Amount of up/down : sh600000
Trading volume : sh600000
Trading amount : sh600000
Buy price : sh600000
Sell price : sh600000
Agency trans : sh600000
Buy 1 : sh600000
Buy 2 : sh600000
Buy 3 : sh600000
Buy 4 : sh600000
Buy 5 : sh600000
Sell 1 : sh600000
Sell 2 : sh600000
Sell 3 : sh600000
Sell 4 : sh600000
Sell 5 : sh600000
成功!