博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#访问gsoap的服务--可用
阅读量:5035 次
发布时间:2019-06-12

本文共 17671 字,大约阅读时间需要 58 分钟。

问题来源:


C++开发一个webservice,然后C#开发客户端,这样就需要C#的客户端访问gsoap的服务端。(大家都知道gsoap是C/C++开发webservice的最佳利器) 为什么不考虑直接用wcf开发webservice?那是考虑到以后有可能要移植到Linux平台。

gsoap实现C#(wpf)客户端调用C++服务器端

首先建立C++服务器端,这里需要使用到gsoap

第一步:自己在桌面建立一个文件夹,命名为add,打开add文件夹,新建txt文档,命名为add.txt,拷贝下面的代码到add.txt,点击保存,然后修改add.txt后缀名为add.h

//gsoap ns service name: add//gsoap ns service namespace: http://localhost/add.wsdl//gsoap ns service location: http://localhost//gsoap ns service executable: add.cgi//gsoap ns service encoding: encoded //gsoap ns schema namespace: urn:add int ns__add( int num1, int num2, int* sum );

第二步:从gsoap文件里面拷贝soapcpp2.exe到add文件夹里面,然后打开cmd命令行,输入:soapcpp2.exe add.h会生成许多文件,如图

这里写图片描述

这里写图片描述
第三步:新建Win32控制台应用程序,命名为:gsoapApplication_1_S;
添加wsock32.lib引用;
从add文件夹中拷贝如下图所示文件到该项目中,其中黑圈里面的两个项目来自gsoap拷贝:
这里写图片描述
第四步:修改gsoapApplication_1_S.cpp,其代码如下:
// gsoapApplication_1_S.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); m = soap_bind(&add_soap, NULL, 4567, 100); if (m < 0) { soap_print_fault(&add_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: master socket = %d/n", 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 = %d/n", s); soap_serve(&add_soap);//该句说明该server的服务 soap_end(&add_soap); } return 0; } //server端的实现函数与addmethod.h中声明的函数相同,但是多了一个当前的soap连接的参数 int ns__add(struct soap *add_soap, int num1, int num2, int *sum) { *sum = num1 + num2; return SOAP_OK; }

第五步:编译成功,打开cmd命令行,输入gsoapApplication_1_S.exe 4567打开主服务,如图

这里写图片描述
第六步:打开IE浏览器,输入::4567 回车,如图所示,服务器端已经配置成功
这里写图片描述

配置C#(wpf)客户端,使用到wsdl.exe,在本地搜索一下,没有的话需要在网上下载一个,我是在网上下载的,下载很简单

第一步:拷贝wsdl.exe到add文件夹,打开vs自带的黑屏命令行工具,输入:wsdl /out add.wsdl回车,会生成.cs文件,文件里面包含多线程、代理等信息,如下图
这里写图片描述

第二步:新建WPF应用程序,命名为gsoapApplication_1_C_WPF,拷贝add.cs,add.wsdl两个文件到该工程中,并把add.cs加入工程,(主要针对用别人的服务没法修改,亦可这样操作:右键点击C#窗口项目的“引用”选择“添加服务引用”,就会出现一个填写wsdl所在地址的对话框,可以选择是远端webservice服务地址下的wsdl,当然也可以是本地的。我选择的是本地地址,也就是C:\add.wsdl,点击“前往”。就会找到服务。这时下面的名字空间最好写的和当初gsoap建立时指定的命名空间一样。其实不一样也可以,但是在项目中使用的时候用的就是这个新的名字了。--wsj建议采用直接拷贝add.cs加入工程使用的方法)修改add.cs文件代码的”“为”“,如图所示:

这里写图片描述

第三步:MainWindow.xaml界面代码如下:

第四步:MainWindow.xaml.cs代码如下:

using System;using System.Collections.Generic;using System.Linq; using System.Text;using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace gsoapApplication_1_C_WPF { ///  /// Interaction logic for MainWindow.xaml ///  public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void submitAdd_Click(object sender, RoutedEventArgs e) { add myadd = new add(); int num1 = Convert.ToInt32(this.num1.Text); int num2 = Convert.ToInt32(this.num2.Text); int? sum = 0; bool sumSpecified = false; myadd.Calladd(num1, num2,out sum, out sumSpecified); this.result.Text = sum.ToString(); } } }

第五步:编译,生成,结果如图所示(不要忘了打开主服务哦~):

这里写图片描述

源码地址:https://files.cnblogs.com/files/liushui-sky/gsoapApplication_1_C_WPF.rar

                 https://files.cnblogs.com/files/liushui-sky/gsoapApplication_1_S.rar

发现新的问题

对于接口.h文件中用自定义的结构体,会出现无法辨识的问题。

例如:

//gsoap ns service name: add//gsoap ns service namespace: http://localhost/add.wsdl//gsoap ns service location: http://localhost//gsoap ns service executable: add.cgi//gsoap ns service encoding: encoded //gsoap ns schema namespace: urn:add int ns__add( int num1, int num2, int* sum ); typedef struct ns__point { int x; int y; }; int ns__addPt(struct ns__point num1, struct ns__point num2, struct ns__point* result );

这里写图片描述

1、C#提供的WebService的URL一般形如:,但是,C++能提供的只能是:。C++做客户端的时候调用没有问题,但是当C#做客户端的时候,引用C++提供的RUL时,会提示没用执行方法(HTTP GET method not implemented)。做C#开发的大部分会认为C++方提供的不是WebService,或者说提供的WebService根本就不全,都不带.asmx文件。做C++开发的会认为他传输的数据符合soap协议,靠http传输数据,他就是WebService。

2、当我们解决了第一步后,紧接着会发现另外一个问题。当我们需要传输自定义数据类型时(在C++中称结构体,在C#中称实体),从C++返回的信息中,C#无法构建出实体类。

3、当传输的信息中带有中文字符时,乱码满天飞。

为了解决这些问题,我们先简单了解一下WebService。

Web Service互操作协议栈:
、服务发现 (UDDI)
、服务描述(WSDL)
、服务调用(SOAP)
、消息编码 (XML)
、传输网络层(HTTP, TCP/IP)
其中WSDL描述WebService都有什么方法、方法有什么参数,什么返回值等。SOAP(简单对象访问协议(Simple Object Access Protocol)是一种轻量的、简单的、基于XML的协议。传输的数据就需要遵循这个协议。我比较简单得认为传输的数据需要遵循这种格式。

借用微软的这个图描述下WebService的调用过程:

这里写图片描述

C++、C写的WebService相互调用martin新浪博客 - mylovejsj - 宋孝先的博客

开始解决问题。作为.NET开发人员,我们根本就接触不到底层的东西,全被封装了。

C++做的确实是WebService,只是他们需要给提供一个描述文档,即.WSDL文件。使用.NET提供的wsdl.exe工具,使用命令:wsdl /o: c:\webservice.cs c:\webservice.wsdl。通过webservice.wsdl文档,生成代理类,将代理类写入webservice.cs文件中。我们拷贝这个cs文件到项目中,将URL指向,就能像以往那样使用WebService了。

当出现无法传递复杂类型数据时,是因为使用gsoap生成的wsdl文件与.Net中生成的wsdl文件不一样。具体代码如下:

以上为gsoap生成的。返回实体result,实体有两个属性:a,b。

以上是.NET生成的。

在下面的文件中,多出

这个便是.NET中用来构造实体的。当我们出现情况4.2时,gsoap中尽量使用.NET生成的wsdl文档,生成.h文件,以避免C++中的结构无法在C#中转换成实体。

第三个问题,我们是通过将中文转换成16进制后传输过来,然后再转换成中文。下面提供C#转换的代码:

/// /// 从16进制转换成汉字 ///  ///  /// 
public static string GetChsFromHex(string hex) { if (hex == null) throw new ArgumentNullException("hex"); if (hex.Length % 2 != 0) { hex += "20";//空格 //throw new ArgumentException("hex is not a valid number!", "hex"); } // 需要将 hex 转换成 byte 数组。 byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < bytes.Length; i++) { try { // 每两个字符是一个 byte。 bytes[i] = byte.Parse(hex.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); } catch { // Rethrow an exception with custom message. throw new ArgumentException("hex is not a valid hex number!", "hex"); } } // 获得 GB2312,Chinese Simplified。 System.Text.Encoding chs = System.Text.Encoding.GetEncoding("gb2312"); return chs.GetString(bytes); } /// /// 从汉字转换到16进制 /// /// ///
public static string GetHexFromChs(string s) { if ((s.Length % 2) != 0) { s += " ";//空格 //throw new ArgumentException("s is not valid chinese string!"); } System.Text.Encoding chs = System.Text.Encoding.GetEncoding("gb2312"); byte[] bytes = chs.GetBytes(s); string str = ""; for (int i = 0; i < bytes.Length; i++) { str += string.Format("{0:X}", bytes[i]); } return str; }

注:以上来转换代码源于网络,C++中转换的代码也可以在网上找到。

例子解决代码

//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.cgi //gsoap ns schema namespace: urn:calc typedef struct ns__point { int x; int y; }; struct ns__pointResponse { int ret; struct ns__point pt; }; int ns__add(int num1, int num2, int* result ); int ns__addPt(struct ns__point num1, struct ns__point num2, struct ns__pointResponse* result );

 

这里写图片描述

图中会写下calc.cs,就说明成功了。
至于为什么这么写就解决问题了,那就要扯到如何生成接口头文件了。

由wsdl文件生成头文件

开发客户端程序

(1)客户端服务端通信必不可少的一个东西:接口定义。
gSoap使用中,需要此接口文件(也就是以后常提到的头文件)此文件可以两种方式得到:
1: 由现有的wsdl文件转换得到(本文使用这种方式)
2: 自己编写
(2)两个工具的用途
wsdl2h.exe——–名字就能看出来,完成 wsdl文件(.wsdl)到(2)头文件(.h)的转换,即由写好的wsdl格式的接口定义文件转换为C/C++格式的头文件
soapcpp2.exe——根据接口头文件生成应用程序客户端和服务端的框架文件(soapClient.cpp、soapServer.cpp等).

结合例子说明过程

示例:引用向导中的例子–计算器
由wsdl文件生成接口头文件
wsdl文件URL地址:
操作流程
a) 程序->运行 输入cmd 启动命令行;
b) 打开wsdl2h.exe所在文件路径(不打开的话下面输入时要记着输入全路径,不然找不着了);
c) 输入:wsdl2h.exe -o cal.h ,
其中
“wsdl2h.exe”,因为第二步中打了wsdl2h文件所在路径,所以此处可以直接用了,若没打开要输入所在完整路径
“cal.h”为生成的头文件名,此文件的保存位置在wsdl2h.exe同一文件目录下(要修改的话要请参照命令行语法规则,此处不多说了,有点脱离主题)
       “-o”是生成选项,表示输出,也可以增加其它选项(向导中出现 “-s -o”、”-c -o”等),具体选项说明请参照向导中介绍。
““是wsdl文件的位置,此处是在网络地址(这个地址是可以用的),如果wsdl文件在本地的也可以,路径设置好就OK了
注意:以上四项中每项间都有空格分开 不要手误啊!
d) 回车 运行吧,看提示信息,没有提示故障的话,查找cal.h吧(cal.h的保存路径要记好啊,自己设置的);
e) 得到cal.h后,打开可以看到接口定义;
f) 在命令行中 输入:soapcpp2.exe cal.h
其中
“soapcpp2.exe”,此处把soapcpp2.exe和wsdl2h.exe放在同一目录下了,且前面已打开此路径;
“cal.h”即由wsdl生成的头文件,此文件保存位置与soapcpp2.exe相同,故此处可这样输入,若不同还须设置文件路径;
同样两项之间也有空格!
可以增加控制选项如”soapcpp2.exe -C cal.h”则只生成客户端所需文件, “soapcpp2.exe -S calc.h”则只生成服务端所需文件
g) 回车 运行。
如果提示找不到文件 stlvector.h,因为cal.h文件中引用了文件stlvector.h;解决方法:开发包\gsoap\import目下有此文件,复制一份到cal.h所在目录。
注意:此过程中要检查生成的编译信息,确保没有警告信息出现(警告信息可能是gSoap不支持的内容,如果不去除,程序运行故障很难找到根本原因),另不能只看编译结果成功就认为是正确的,存在警告信息也显示为编译成功!!
h) 编译成功,生成的框架文件保存位置与cal.h在同一目录下,包括:calc.nsmap、soapC.cpp、soapcalcObject.h、soapcalcProxy.h、soapClient.cpp、soapClient.lib
、soapH.h、soapServer.cpp、soapServer.Lib、soapStub.h和接口的请求应答xml文件。
    其中
      calc.nsmap 为命名空间定义文件;
      soapClient.cpp 客户端文件
      soapServer.cpp 服务端文件
      soapcalcProxy.h 代理用到
      soapStub.h 此文件中为程序中要用到的接口的声明(将cal.h中的接口经过处理后,在程序中供调用的接口)
      xml文件 为接口的xml格式,可以据此帮助调试等。。。
其它文件作用还没完全搞明白,向导中有说明,此处不说了以免误导^_^
i) 编译过程完成。下面开始程序(客户端)
VC6中新建空的win32控制台工程,新建源文件calcClient.cpp;
复制编译生成的文件(包括cal.h和stlvector)到程序目录中;
在工程中添加文件calc.nsmap、soapC.cpp、soapClient.cpp、soapH.h、soapStub.h(使用代理添加soapcalcProxy.h);
编译,提示无法找到文件stdsoap2.h、stdsoap2.cpp文件,这两个文件为gSoap的源码文件,在\gsoap文件夹中找到这两个文件,复制到程序目录下并添加到工程中;
在calcClient.cpp文件中 添加语句#include “soapH.h”, #include “calc.nsmap”
///calcClient.cpp源码//

#include 
#include "soapH.h"#include "calc.nsmap"const char server[] = "http://websrv.cs.fsu.edu/~engelen/calcserver.cgi"; int main(int argc, char **argv) { struct soap soap; double a, b, result; if (argc < 4) { fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n"); exit(0); } soap_init(&soap); a = strtod(argv[2], NULL); b = strtod(argv[3], NULL); switch (*argv[1]) { case 'a': soap_call_ns2__add(&soap, server, "", a, b, result); break; case 's': soap_call_ns2__sub(&soap, server, "", a, b, result); break; case 'm': soap_call_ns2__mul(&soap, server, "", a, b, result); break; case 'd': soap_call_ns2__div(&soap, server, "", a, b, result); break; case 'p': soap_call_ns2__pow(&soap, server, "", a, b, result); break; default: fprintf(stderr, "Unknown command\n"); exit(0); } if (soap.error) { soap_print_fault(&soap, stderr); exit(1); } else printf("result = %g\n", result); soap_destroy(&soap); soap_end(&soap); soap_done(&soap); return 0; }

其中soap_call_ns2__add、soap_call_ns2__sub、soap_call_ns2__mul、soap_call_ns2__div、soap_call_ns2__pow为接口函数,在soapStub.h中可以找到函数声明。

自定义接口头文件

接口头文件的格式在向导中没有看到明确的说明性的内容,但通过看开发包中示例程序中头文件定义和通过wsdl生成的头文件的内容,可以发现,头文件中都会出现以下几行信息

//gsoap ns service name: calc Simple calculator service
//gsoap ns service style: rpc
//gsoap ns service encoding: encoded
//gsoap ns service namespace:
//gsoap ns service location:
//gsoap ns service method-style: add rpc
//gsoap ns service method-encoding: add
//gsoap ns service method-action: add “”
这些都是头文件中的说明性信息,编译时会用到这里的信息,这些信息有命名空间的和服务名称的名字,有些信息为默认参数信息,如service location 如果在客户端调用接口方法时,没有输入服务端地址,方法执行时将自动调用此处的地址做为服务器地址。后三行是对add方法的说明,在写头文件时可以修改一下这些说明信息如下:
//gsoap ns service name: calc Simple calculator service
//gsoap ns service style: rpc
//gsoap ns service namespace: urn:calc
//gsoap ns service location:
这些信息是很重要的,如果是已定义好的接口,一定要注意命名空间名字统一。

注:--wsj

    关于红色部分说明--还是有点模糊

    

二 命名空间
 
  
   
0.0   
0.0  
   由于标签是我们自定义的,多个XML文件中可能存在重复命名,但表示的含义却不一样,为了解决XML文档中命名的冲突问题 就出现了命名空间。所以需要加上一个namespace来区分多个xml文件之间相同的标签。使用语法:xmlns:namespace-prefix="namespaceURI"xmlns的意思是XML Namespace URI是Uniform Resource Identifier 的缩写,作用是赋予命名空间一个惟一的名称用来表示URI 一个是URL,一个是URN,gSOAP中URL和URN都使用了:xmlns:ns="urn:calc 其中calc是一个接口文件的文件名。这句是gsoap定义的默认命名空间有了默认的命名空间,直接是
0.0就可以,而不用
0.0
转自:https://blog.csdn.net/u013898698/article/details/55511284

  

下面开始主要工作:接口定义
gSoap对“”和“_”(下划线、双下划线)有特殊用法,接口定义时函数名前要加上命名空间名和双下划线
举例:加法运算
int add(int num1, int num2, int &num3);
在接口头文件定义时要写成如下格式
int ns__add(int num1, int nmu2, int &num3);
其中
“ns”是命名空间名称,此名称可以自定义成其它名字 但其后”urn:calc”不可随意更改,这个是要与服务端统一的
“__”是编译时识别符号,如果没有的话xml文件是编译不出来的

“_”(单下划线)定义名称中要慎用,自己定义的变量或函数名称中使用下划线的地方要在下划线后加上”USCORE”;

例 定义 ns__add_sum(int num_1, int num2, int &num_3);
要写成如下形式
ns__add_USCOREsum(int num_USCORE1, int num2, int &num_USCORE3);
“add”是接口函数名 这个是客户端与服务器统一的接口名字
函数内参数变量类型和变量名 为客户端与服务器统一的接口
函数中只有最后一个参数是输出参数,前面的都是输入参数
若有多个输出信息,可定义结构体。
若没有输入参数 可将输入参数类型定义为void (将忽略void 类型的参数)
函数返回类型必须为 int,可以通过返回值判断接口函数执行情况
至此接口定义要注意的地方完毕,开始写接口定义文件。
本例中使用自定义的头文件,编写客户端程序,但服务器仍与上篇中服务器相同,以便说明两种方式的结果,接口可以从上篇中由wsdl生成的头文件中获得。
源码如下:

///////////////mycalc.h/////////////////////////// //gsoap ns service name: mycalc //gsoap ns service style: rpc //gsoap ns service namespace: urn:calc //gsoap ns service location: http://websrv.cs.fsu.edu/~engelen/calcserver.cgi int ns__add(double a, double b, double &result); int ns__sub(double a, double b, double &result); int ns__mul(double a, double b, double &result); int ns__div(double a, double b, double &result); int ns__pow(double a, double b, double &result); ///////////////mycalc.h///////////////////////////

上面文件中一定要注意 //gsoap ns service namespace: urn:calc 由于服务器中接口命名空间为calc 故此处必须是calc! ---这句还是没明白wsj

开始编译此头文件
运行 soapcpp2.exe mycalc.h
编译成功,写客户端程序
新建工程mycalcClient, 添加生成的文件,新建源文件mycalcClient.cpp
源码如下

//////////////////////mycalcClient.cpp///////////////// #include 
#include "soapH.h" #include "calc.nsmap" const char server[] = "http://websrv.cs.fsu.edu/~engelen/calcserver.cgi"; int main(int argc, char **argv) { struct soap soap; double a, b, result; if (argc < 4) { fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n"); exit(0); } soap_init(&soap); a = strtod(argv[2], NULL); b = strtod(argv[3], NULL); switch (*argv[1]) { case 'a': soap_call_ns__add(&soap, server, "", a, b, result); break; case 's': soap_call_ns__sub(&soap, server, "", a, b, result); break; case 'm': soap_call_ns__mul(&soap, server, "", a, b, result); break; case 'd': soap_call_ns__div(&soap, server, "", a, b, result); break; case 'p': soap_call_ns__pow(&soap, server, "", a, b, result); break; default: fprintf(stderr, "Unknown command\n"); exit(0); } if (soap.error) { soap_print_fault(&soap, stderr); exit(1); } else printf("result = %g\n", result); soap_destroy(&soap); soap_end(&soap); soap_done(&soap); return 0; } //////////////////////mycalcClient.cpp/////////////////

测试一下吧^_^

对比两种生成接口头文件的方法,选择那一种还要视情况而定
如果是已有写好的wsdl文档,当然是选择用wsdl2h工具来生成头文件了,毕竟这个方便的多,但在编译时,一定要检查警告信息,有些情况下生成的接口头件存在编译异常,例如复杂数据结构时就有可能出现结构体命名不符合gSoap命名规则(实际应用中遇至过,此时要手动修改这些命名)
简单说一下soap结构体初始化及清理
soap_init(&soap);//初始化
…………
soap_destroy(&soap);//结束清理操作
soap_end(&soap);
soap_done(&soap);
向导中这方面讲的比较细^_^
两篇都只是写了客户端的程序,因为是一直在与现成的服务器端通信,在此就没列出自己的服务器程序;

接口定义

,可参考《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 ); 即,结构体中的第一个域会变成返回值,其他的变成一个个的输出参数。--wsj 待验证

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, len+1 ); for( i=len-1, j=0; i>=0; 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;

  1. 使用下面得函数转换我们的传输内容,即将我们的数据转成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; }

Reference:[gsoap使用总结]()

转自:https://blog.csdn.net/caowei880123/article/details/49129211?locationNum=3&fps=1

转载于:https://www.cnblogs.com/liushui-sky/p/9722217.html

你可能感兴趣的文章
jquery自动生成二维码
查看>>
spring回滚数据
查看>>
新浪分享API应用的开发
查看>>
美国专利
查看>>
【JavaScript】Write和Writeln的区别
查看>>
百度编辑器图片在线流量返回url改动
查看>>
我对你的期望有点过了
查看>>
微信小程序wx:key以及wx:key=" *this"详解:
查看>>
下拉框比较符
查看>>
2.2.5 因子的使用
查看>>
css选择器
查看>>
photoplus
查看>>
Python 拓展之推导式
查看>>
[Leetcode] DP-- 474. Ones and Zeroes
查看>>
80X86寄存器详解<转载>
查看>>
c# aop讲解
查看>>
iterable与iterator
查看>>
返回顶部(动画)
查看>>
webpack+react+antd 单页面应用实例
查看>>
Confluence 6 SQL Server 数据库驱动修改
查看>>