[转载]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 Service互操作协议栈:

<A>、服务发现 (UDDI)

<B>、服务描述(WSDL)

<C>、服务调用(SOAP)

<D>、消息编码 (XML)

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

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

借用微软的这个图描述下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 -->
  <element name="result">
   <complexType>
    <sequence>
     <element name="a" type="xsd:int" minOccurs="1" maxOccurs="1"/>
     <element name="b" type="xsd:int" minOccurs="1" maxOccurs="1"/>
    </sequence>
   </complexType>
  </element>

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

<s:element name="TestResponse">
    <s:complexType>
     <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="TestResult" type="tns:result" />
     </s:sequence>
    </s:complexType>
   </s:element>
   <s:complexType name="result">
    <s:sequence>
     <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int" />
     <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int" />
    </s:sequence>
   </s:complexType>

以上是.NET生成的。

在下面的文件中,多出

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

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

/// <summary>
        /// 从16进制转换成汉字
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        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);
        }

/// <summary>
        /// 从汉字转换到16进制
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        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++中转换的代码也可以在网上找到。

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

[转载]C++、C#写的WebService相互调用的更多相关文章

  1. [转贴]C++、C#写的WebService相互调用

    以下宏文(原文在 http://blog.sina.com.cn/s/blog_4e7d38260100ade4.html),是转贴并进行了修饰编辑: 首先感谢永和兄提供C++的WebService服 ...

  2. C++和C# WebService相互调用

    C#调用C++ gSOAP: 调用http://blog.csdn.net/ggz631047367/article/details/44567411的服务http://127.0.0.1:8089/ ...

  3. .NET调用Java写的WebService

    最近遇到一个用.net调用java写的webservice的应用,对方程序员提供了一个后缀为wsdl的文件,这个跟.Net里面生成的wsdl文件差不多,起初没什么概念就查了点资料,知道可以将这个wsd ...

  4. 在Android中调用C#写的WebService(附源代码)

    由于项目中要使用Android调用C#写的WebService,于是便有了这篇文章.在学习的过程中,发现在C#中直接调用WebService方便得多,直接添加一个引用,便可以直接使用将WebServi ...

  5. 用delphi的THTTPRIO控件调用了c#写的webservice。

    用delphi的THTTPRIO控件调用了c#写的webservice. 下面是我调试时遇到的一些问题: 1,导入wsdl文件:file--new----other----wenservice---W ...

  6. delphi7调用java写的webservice,在调用的时候弹出“wssecurityhandler:request does not contain required security header”

    delphi7调用java编写的webservice问题我用delphi7调用java写的webservice,在调用的时候弹出“wssecurityhandler:request does not ...

  7. python模块--如何相互调用自己写的模块

    一.模块相互调用同级目录调用时的两种方法 import module print(module.add(3,8)) from module import add print(add(2,4)) 同级目 ...

  8. 转载 OS js oc相互调用(JavaScriptCore) ---js调用iOS ---js里面直接调用方法

    OS js oc相互调用(JavaScriptCore)   接着上节我们讲到的iOS调用js 下来我们使用js调用iOS js调用iOS分两种情况 一,js里面直接调用方法 二,js里面通过对象调用 ...

  9. 转载 iOS js oc相互调用(JavaScriptCore) --iOS调用js

    iOS js oc相互调用(JavaScriptCore)   从iOS7开始 苹果公布了JavaScriptCore.framework 它使得JS与OC的交互更加方便了. 下面我们就简单了解一下这 ...

随机推荐

  1. Python基础第八天

    一.内容

  2. bzoj3160

    fft+manacher fft都快忘了... 其实我们发现,这个问题是可以用fft做的,因为是回文子序列,所以我们直接自己和自己求卷积,然后扫描每个位置,注意是每个位置,因为包括奇数长度和偶数长度, ...

  3. bzoj 4596

    4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 257  Solved: 152[Submit][Sta ...

  4. myeclipse 导入maven

    一安装maven 先安装jdk,配置JAVA_HOME 把下载的maven bin包,解压到指定目录,比如:D:\apache-maven-3.3.9-bin 配置maven的系统变量M2_HOME和 ...

  5. Excel -- 实用技巧

    一起来学习这45个职场Excel小窍门,轻轻松松提高工作效率,超实用,新技能get! 1.快速填充公式的三种方式 2.最快求和 3.添加文字下面线条的2种方法 4.设置列宽的3种方法 5.以cm为单位 ...

  6. 洛谷 P3356 火星探险问题 【最大费用最大流】

    输出方案好麻烦啊 拆点,石头的连(i,i',1,1)(i,i',inf,0)表示可以取一次价值1,空地直接连(i,i',inf,0),对于能走到的两个格子(不包括障碍),连接(i',j,inf,0), ...

  7. 洛谷P4303 [AHOI2006]基因匹配(树状数组)

    传送门 我已经连这种傻逼题都不会了orz 正常的dp是$O(n^2)$的,枚举第一个数组的$j$,然后第二个数组的$k$,如果相等,则$dp[i]=dp[j]+1$,否则$dp[i]=dp[j]$ 然 ...

  8. 洛谷 P3332 [ZJOI2013]K大数查询 || bzoj3110

    用树套树就很麻烦,用整体二分就成了裸题.... 错误: 1.尝试线段树套平衡树,码农,而且n*log^3(n)慢慢卡反正我觉得卡不过去 2.线段树pushdown写错...加法tag对于区间和的更新应 ...

  9. 逆序数 UVALive 6508 Permutation Graphs

    题目传送门 /* 题意:给了两行的数字,相同的数字连线,问中间交点的个数 逆序数:第一行保存每个数字的位置,第二行保存该数字在第一行的位置,接下来就是对它求逆序数 用归并排序或线段树求.想到了就简单了 ...

  10. 题解报告:hdu 1284 钱币兑换问题(简单数学orDP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1284 Problem Description 在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很 ...