`
jiagou
  • 浏览: 2530249 次
文章分类
社区版块
存档分类
最新评论

C++、C#写的WebService相互调用

 
阅读更多

首先感谢永和兄提供C++的WebService服务器端及客户端,并且陪我一起熬夜;然后是火石和我做接口的兄弟,虽然都不知道你叫什么,如果没有你的合作,东西也没那么快完成。

一、由于公司运营火石的《西游Q记》,火石采用的是C++作为开发语言,Unix平台,而我们一直使用Windows操作平台,.NET快速开发。我们之间需要数据的通讯,所以需要利用WebService实现跨平台的数据通讯。尽管WebService是跨平台的,但是实现起来却并不容易。

二、用C#实现WebService是相当简单的事情,我们只要创建一个Web服务程序,在方法名上面加上[WebMethod],部署到IIS上,就能像访问Web站点一样访问WebService。用C#编写客户端时,只需要将WebService添加到引用,就能像调用本地方法一样去调用WebService。像这样的例子也比比皆是,在这就不多讲。

三、用C++实现WebService,一般会用到gsoap,具体方法见:http://www.cppblog.com/qiujian5628/archive/2008/06/19/54019.html

四、当做完了这些之后,并不代表WebService就能相互通讯了,现在我简单列举一下问题:

1、C#提供的WebService的URL一般形如:http://localhost/WebService.asmx,但是,C++能提供的只能是:http://localhost/。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 <wbr>Service互操作协议栈:</wbr>

<A>、服务发现 <wbr>(UDDI)</wbr>

<B>、服务描述(WSDL)

<C>、服务调用(SOAP)

<D>、消息编码 <wbr>(XML)</wbr>

<E>、传输网络层(HTTP, <wbr>TCP/IP)</wbr>

其中WSDL描述WebService都有什么方法、方法有什么参数,什么返回值等。SOAP(简单对象访问协议(Simple Object Access Protocol)是一种轻量的、简单的、基于XML的协议。传输的数据就需要遵循这个协议。我比较简单得认为传输的数据需要遵循这种格式。

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

[转载]C++、C#写的WebService相互调用

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

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

http://localhost/,就能像以往那样使用WebService了。

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

<!-- operation response element -->
<wbr>&lt;element name="result"&gt;<br><wbr><wbr>&lt;complexType&gt;<br><wbr><wbr><wbr>&lt;sequence&gt;<br><wbr><wbr><wbr><wbr>&lt;element name="a" type="xsd:int" minOccurs="1" maxOccurs="1"/&gt;<br><wbr><wbr><wbr><wbr>&lt;element name="b" type="xsd:int" minOccurs="1" maxOccurs="1"/&gt;<br><wbr><wbr><wbr>&lt;/sequence&gt;<br><wbr><wbr>&lt;/complexType&gt;<br><wbr>&lt;/element&gt;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

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

<s:element name="TestResponse">
<wbr><wbr><wbr><wbr>&lt;s:complexType&gt;<br><wbr><wbr><wbr><wbr><wbr>&lt;s:sequence&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr>&lt;s:element minOccurs="0" maxOccurs="1" name="TestResult" type="tns:result" /&gt;<br><wbr><wbr><wbr><wbr><wbr>&lt;/s:sequence&gt;<br><wbr><wbr><wbr><wbr>&lt;/s:complexType&gt;<br><wbr><wbr><wbr>&lt;/s:element&gt;<br><wbr><wbr><wbr>&lt;s:complexType name="result"&gt;<br><wbr><wbr><wbr><wbr>&lt;s:sequence&gt;<br><wbr><wbr><wbr><wbr><wbr>&lt;s:element minOccurs="1" maxOccurs="1" name="a" type="s:int" /&gt;<br><wbr><wbr><wbr><wbr><wbr>&lt;s:element minOccurs="1" maxOccurs="1" name="b" type="s:int" /&gt;<br><wbr><wbr><wbr><wbr>&lt;/s:sequence&gt;<br><wbr><wbr><wbr>&lt;/s:complexType&gt;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

以上是.NET生成的。

在下面的文件中,多出

<s:element name="TestResponse">
<wbr><wbr><wbr><wbr>&lt;s:complexType&gt;<br><wbr><wbr><wbr><wbr><wbr>&lt;s:sequence&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr>&lt;s:element minOccurs="0" maxOccurs="1" name="TestResult" type="tns:result" /&gt;<br><wbr><wbr><wbr><wbr><wbr>&lt;/s:sequence&gt;<br><wbr><wbr><wbr><wbr>&lt;/s:complexType&gt;<br><wbr><wbr><wbr>&lt;/s:element&gt;<br> 这个便是.NET中用来构造实体的。当我们出现情况4.2时,gsoap中尽量使用.NET生成的wsdl文档,生成.h文件,以避免C++中的结构无法在C#中转换成实体。</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

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

/// <summary>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// 从16进制转换成汉字<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// &lt;/summary&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// &lt;param name="hex"&gt;&lt;/param&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// &lt;returns&gt;&lt;/returns&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>public static string GetChsFromHex(string hex)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>if (hex == null)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>throw new ArgumentNullException("hex");<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>if (hex.Length % 2 != 0)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>hex += "20";//空格<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>//throw new ArgumentException("hex is not a valid number!", "hex");<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>// 需要将 hex 转换成 byte 数组。<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>byte[] bytes = new byte[hex.Length / 2];</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

for (int i = 0; i < bytes.Length; i++)
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>try<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>// 每两个字符是一个 byte。<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>bytes[i] = byte.Parse(hex.Substring(i * 2, 2),<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>System.Globalization.NumberStyles.HexNumber);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>catch<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>// Rethrow an exception with custom message.<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>throw new ArgumentException("hex is not a valid hex number!", "hex");<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

// 获得 GB2312,Chinese Simplified。
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>System.Text.Encoding chs = System.Text.Encoding.GetEncoding("gb2312");</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>


<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>return chs.GetString(bytes);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

/// <summary>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// 从汉字转换到16进制<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// &lt;/summary&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// &lt;param name="s"&gt;&lt;/param&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>/// &lt;returns&gt;&lt;/returns&gt;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>public static string GetHexFromChs(string s)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>if ((s.Length % 2) != 0)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>s += " ";//空格<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>//throw new ArgumentException("s is not valid chinese string!");<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

System.Text.Encoding chs = System.Text.Encoding.GetEncoding("gb2312");

byte[] bytes = chs.GetBytes(s);

string str = "";

for (int i = 0; i < bytes.Length; i++)
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>str += string.Format("{0:X}", bytes[i]);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

return str;
<wbr><wbr><wbr><wbr><wbr><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr>

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

三大难题到此结束,其实在整个过程中还有个最大的难题,那就是人与人的交流。因为一方使用C++,一方使用C#,语言不同,各自想问题的方式也不一样,所以需要相互理解,相互站在对方的角度想问题。多交流、多沟通才是解决问题之道。请不要抱怨C#弱智,也请不要怪C++繁琐,语言既然存在则有他的价值。

分享到:
评论

相关推荐

    C++、C#写的WebService(gsoap)相互调用

    用C#编写客户端时,只需要将WebService添加到引用,就能像调用本地方法一样去C# WebService调用。像这样的例子也比比皆是,在这就不多讲。 二、用C++实现WebService,一般会用到gsoap,具体方法见:...

    VS2015 C++和C++的通过SOAP的WebService,C++和C#的WebService发布和调用

    VS2015 C++和C++的通过SOAP的WebService,C++和C#的WebService发布和调用

    C++2005调用C#Webservice接口返回值为List

    C++2005调用C#Webservice接口返回值为List,C++2005调用C#Webservice接口返回值为List

    使用C#创建webservice服务,并使用服务接口

    使用C#创建webservice服务,并使用服务接口得到C#动态库。然后可以使用C++程序调用

    C#调用WebService.pdf

    C#调用WebService.pdf

    C++ WebService

    这是一个完整的工程,可以直接运行,内容包括: 里面有个C#做WebService服务DLL,用C++调用这个C#的DLL,以实现,C++在使用WebService时,总是用GSOAP这种麻烦的东西搞来搞去。

    使用GSOAP调用C#写的WebService

    基于gSOAP编译工具的C++客户端调用C#服务器端WebService示例程序; gSOAP编译工具使用说明文档; gsoap_win32_2.7.6c压缩包

    C++使用gsoap调用webservice接口

    C++使用gsoap调用webservice接口,无需积分,仅供参考,内置说明文档,欢迎下载。

    VS2015 C++操作WebService

    C++调用C#WebService,在VS2015下测试通过。

    多语言调用WebService技术文档.doc

    内容概要:代码示例 C++调用WebService,Java调用WebService,C#调用WebService,Js调用WebService,VB调用WebService,ASP调用WebService,PHP调用WebService。 适用人群:WebService开发人员 使用场景:跨平台...

    VS2015 C++和C++的通过SOAP的WebService,gsoap工具

    VS2015 C++和C++的通过SOAP的WebService,C++和C#的WebService发布和调用

    C#+MySQL 实现webservice对数据信息的查询

    C#+MySQL 实现webservice对数据信息的查询 采用了一种简单的加密通信 即在调用webservice方法时,采用多种参数输入的方式进行验证。 返回结果为结构体 ,方便java、C++调用

    C#调用C++底层代码

    因此, Application = Code + Markup的作者Petzold才会把这本书的结构写成先用以C#来写WPF程序,后半部才介绍XAML。 避免大家误解 WPF = XAML。 XAML还可以用在WF上,所以并不局限于WPF。 如果用了XAML,以为这就是WPF...

    C#调用和实现WebService,纯手工打造!

    先为啥要纯手工打造呢,因为对方是用C++做的,我按照他们给出的WSDL实现了一...HttpWebRequest类可以简单的实现WebService调用。   首先手工打造SOAP包内容 代码如下:string soap = “&lt;soapenv:Envelope xmlns:s

    C#调用java组件SatJni1.2

    SatJni是C++编写的动态链接库,实现了C#,PB,Delphi,VB,VC等对Java的调用,能让你很容易地调用成熟的java类库和第三方java组件。不用再为移值java代码而烦恼。 示例中演示了通过java调用webservice服务(无需代理...

    PB调用java组件SatJni

    SatJni是C++编写的动态链接库,实现了C#,PB,Delphi,VB,VC等对Java的调用,能让你很容易地调用成熟的java类库和第三方java组件。不用再为移值java代码而烦恼。 示例中演示了PB调用webservice服务(无需代理对象)得到...

Global site tag (gtag.js) - Google Analytics