自己学习做网站,乡村网站建设,生产管理软件erp,天津设计网站公司From: http://www.cnblogs.com/linxr/archive/2011/10/17/2215285.html 用C实现WebService#xff0c;gsoap是最好的选择了。近一个月都在折腾这个#xff0c;做个总结吧#xff0c;估计会写得比较长。因为其中碰到了不少问题#xff0c;但最终都解决调了。 …From: http://www.cnblogs.com/linxr/archive/2011/10/17/2215285.html 用C实现WebServicegsoap是最好的选择了。近一个月都在折腾这个做个总结吧估计会写得比较长。因为其中碰到了不少问题但最终都解决调了。 快速开始 1. gsoap官网。遇到问题时官网往往是最能提供帮助的地方。 http://gsoap2.sourceforge.net/ 2. 几个值得参考的链接。 GSoap使用心得 http://www.cppblog.com/qiujian5628/archive/2008/10/11/54019.html GSoap接口定义 http://blog.sina.com.cn/s/blog_5ee9235c0100de3g.html 测试代码。 我是在linux下用C开发的那就Makefile入手吧。至于服务端的代码和客户端的代码可以参考《GSoap使用心得》或者是gsoap自带的例子。 a. 用soapcpp2生产gsoap相关代码 $(GSOAP_BIN)/soapcpp2 -c -x ${WSNAME}.h b. 服务端所需的代码 soapC.c soapServer.c stdsoap2.c c. 客户端所需的代码 soapC.c soapClient.c stdsoap2.c d. 其中stdsoap2.c是从gsoap开发包中复制过来的他的文件是(a)中命令产生的。 -------------分隔符------------------------------------ GSOAP_BIN/usr/local/gSOAP/bin WSNAME0soap WSNAMESmsWBS SERVER_OBJS$(WSNAME0)C.o $(WSNAME0)Server.o stdsoap2.o ${WSNAME}server.o CLIENT_OBJS$(WSNAME0)C.o $(WSNAME0)Client.o stdsoap2.o ${WSNAME}client.o AA_OBJS$(WSNAME0)C.o $(WSNAME0)Server.o $(WSNAME0)Client.o stdsoap2.o ${WSNAME}server.o ${WSNAME}client.o
INCLUDE LIBS CCg -g -DWITH_NONAMESPACES
#LIBS-lz -lc -lncurses -lssl -lcrypto #CCg -g -DWITH_NONAMESPACES -DWITH_OPENSSL
all:server all:client ${WSNAME}.wsdl:${WSNAME}.h $(GSOAP_BIN)/soapcpp2 -c -x ${WSNAME}.h
$(AA_OBJS):%.o:%.c $(CC) -c $? $(INCLUDE)
server:Makefile ${WSNAME}.wsdl $(SERVER_OBJS) $(CC) $(SERVER_OBJS) $(LIBS) -o Smsserver -lpthread
client:Makefile ${WSNAME}.wsdl $(CLIENT_OBJS) $(CC) $(CLIENT_OBJS) $(LIBS) -o Smsclient
clean: rm -f *.o *.xml *.a *.wsdl *.nsmap \ $(WSNAME0)H.h $(WSNAME0)C.c $(WSNAME0)Server.c $(WSNAME0)Client.c \ $(WSNAME0)Stub.* $(WSNAME)$(WSNAME)Proxy.* $(WSNAME)$(WSNAME)Object.* \ $(WSNAME0)ServerLib.c $(WSNAME0)ClientLib.c $(WSNAME)server ns.xsd $(WSNAME)test
clear: rm -f *.o ns.xsd -------------分隔符------------------------------------ 接口定义可参考《GSoap接口定义》。这里我将给出C#引用这个webserver所对应的接口形式。 gsoap是根据我们定义好的.h文件然后用工具产生了我们所需的.c文件。所以我们必须根据gsoap的要求编写.h。 1. 单个参数的传出 int ns__add( int a, int b, int *c ); 需要说明的是这里的ns__是必须的必须以开始注释中的ns加两个下划线开始。返回值必须是int。 但是这里的int并不是接口的返回值而是gsoap内部的返回值。真正的返回值是int *c。 C#中对应的接口: int add( int a, int b ); 返回值就是上述的int *c参数。 2. 多个参数传出在接口中必须使用结构体 typedef char * xsd__string; typedef long xsd__int; struct ns__personResponse{ xsd__int age; xsd__string name; xsd__string address; }; int ns__person( xsd__string buf_in, struct ns__personResponse * buf_out ); 在C#中并不是我们所声明的这样。而是int person( string buf_in, out string name, out string address ); 即结构体中的第一个域会变成返回值其他的变成一个个的输出参数。 3. 返回结构体。如果要返回结构图那么必须在结构体中再套一层结构体 typedef char * xsd__string; typedef long xsd__int; struct ns__person{ xsd__int age; xsd__string name; xsd__string address; }; struct ns__personResponse{ xsd__int ret; struct ns__person person; }; int ns__person( xsd__string buf_in, struct ns__personResponse * buf_out ); 那么在C#中看到的接口是这样的int person( string buf_in, person对应的结构类 ); 4. 接口中的下划线如果接口中的交易名有下划线必须这么声明 int ns__echo_USCOREreverse( char * buf_in, char ** buf_out ); 那么C#中实际上的接口名就是string echo_reverse( string buf_in ); gsoap中返回字符串 1. 下面是一个逆转字符串的函数。 int ns__echo_USCOREreverse( char * buf_in, char ** buf_out ); int ns__echo_USCOREreverse( struct soap *add_soap, char *buf_in, char **buf_out ) { int i, j, len; printf( ns__interface: in[%s]\n, buf_in ); len strlen(buf_in); *buf_out (char*)soap_malloc( add_soap, len1 ); for( ilen-1, j0; i0; i--, j ){ (*buf_out)[j] buf_in[i]; } (*buf_out)[j] 0; return 0; } 其中调用soap_malloc申请空间并且将他赋给返回参数buf_out。这个空间会在调用soap_end时被释放。 gsoap传输中文。我使用utf-8编码格式来支持汉字的传输。 1. 设置gsoap为utf-8传输数据 soap_set_mode( SmsWBS_soap, SOAP_C_UTFSTRING ); //设置编码 SmsWBS_soap.mode|SOAP_C_UTFSTRING; 2. 使用下面得函数转换我们的传输内容即将我们的数据转成UTF-8编码 int conv_charset( const char *dest, const char *src, char *input, size_t ilen, char *output, size_t olen ) { int convlen olen; iconv_t conv iconv_open( dest, src ); if( conv (iconv_t) -1 ) return -1; memset( output, 0, olen ); if( iconv( conv, input, ilen, output, olen ) ){ iconv_close(conv); return -1; } iconv_close(conv);return convlen-olen;}例子 conv_charset( UTF-8, GBK, 林学任.linxr, strlen(林学任.linxr), buf_out-name, 100 );webserver发布1. 在C#中可以直接引用一个webserver但是我们写得webserver如何能用被其引用呢。其实只要实现gsoap的fget回调函数即可SmsWBS_soap.fget http_get;2. http_get函数实现int http_get(struct soap * soap){ FILE *fd NULL;char *s strchr( soap-path, ? );if( !s || strcmp( s, ?wsdl ) ){return SOAP_GET_METHOD;}fd fopen( SmsWBS.wsdl, rb );if (!fd){return 404;}soap-http_content text/xml;soap_response(soap, SOAP_FILE);for (;;){ size_t r fread(soap-tmpbuf, 1, sizeof(soap-tmpbuf), fd);if( !r ){break;}if( soap_send_raw( soap, soap-tmpbuf, r) ){break; }}fclose(fd);soap_end_send(soap);return SOAP_OK;}