首先感谢永和兄提供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时,会提示没用执行方法(HTTPGET method notimplemented)。做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 AccessProtocol)是一种轻量的、简单的、基于XML的协议。传输的数据就需要遵循这个协议。我比较简单得认为传输的数据需要遵循这种格式。

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

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

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

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

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

<!-- operation responseelement -->
  <elementname="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:elementname="TestResponse">
    <s:complexType>
     <s:sequence>
      <s:elementminOccurs="0" maxOccurs="1" name="TestResult" type="tns:result"/>
     </s:sequence>
    </s:complexType>
   </s:element>
   <s:complexTypename="result">
    <s:sequence>
     <s:elementminOccurs="1" maxOccurs="1" name="a" type="s:int"/>
     <s:elementminOccurs="1" maxOccurs="1" name="b" type="s:int"/>
    </s:sequence>
   </s:complexType>

以上是.NET生成的。

在下面的文件中,多出

<s:elementname="TestResponse">
    <s:complexType>
     <s:sequence>
      <s:elementminOccurs="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>
       /// <paramname="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>
       /// <paramname="s"></param>
       ///<returns></returns>
       public static string GetHexFromChs(string s)
       {
           if ((s.Length % 2) != 0)
           {
               s += " ";//空格
               //throw new ArgumentException("s is not valid chinesestring!");
           }

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++繁琐,语言既然存在则有他的价值。

===========================================2012-07-19补=================================

typedef char* String;

1.函数声明如:

class Result

{

public:

Int ErrorCode;

String Description;

};

int ns1__Register(String Account,Result &RegisterResult);//1.创建帐号

ns1__ webservice的名字空间

2.数组声明例如:

class Group

{

public:

Int ID;

Int Version;

String Name;

Int State;

String TestIP;

};

class LoginServer

{

public:

String IP;

Int Port;

};

class ArrayOffGroup

{

public:

Group *__ptr;

int __size;

};

class ArrayOffLoginServer

{

public:

LoginServer *__ptr;

int __size;

};

class ResultGetGameGroupList

{

public:

Int ErrorCode;

String Description;

ArrayOffGroup Groups;

ArrayOffLoginServer LoginServers;

};

int ns1__GetGameGroupList(void *_,ResultGetGameGroupList&GetGameGroupListResult);//2.获取当前启动的服务器组及服务器压力

3.用gSoap工具从*.h生成C++代码及*.wsdl文件

soapcpp2.exe *.h生成WebService的C++代码

注:这里生成的*.wsdl无法用VS的wsdl工具直接生成.net的代理类,需要手动打开*.wsdl把里面的String改为.net认识的string即可.无法直接把char*typedef 成string 这样的话会使生成的c++代码无法编译通过

4.用gSoap工具从*.wsdl生成C++代码

(1).wsdl2h.exe *.wsdl生成 *.h 文件

(2).soapcpp2.exe*.h生成Webservice的C++代码

5.用Vs的wsdl工具生成.net代理类命令

wsdl /out:C:/myProxyClass.cs *.wsdl

附录1.

php调用gSoap的WebService的代码示例:

<?php

echo "start";

header ( "Content-Type: text/html;charset=utf-8" );

$client = new SoapClient ();

try

{

$params = array('Account'=> 'testtest', 'Password' =>'12341234', 'IP' => '127.0.0.1', 'IsAdult'=> 1, 'Presentee' => 1);

$result =$client->__soapCall("Register"

, array( 'parameters' =>$params)

, array('location' =>'http://url:81', 'uri' =>'ns1'));

echo ($result);

}

catch(SoapFault $fault)

{

echo($fault->faultstring);

}

?>

C++、C#写的WebService相互调用相关推荐

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

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

  2. android wsdl封装,在Android中调用C#写的WebService(附源代码)

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

  3. delphi 调用 c# 写的webservice

    调用helloWorld的返回值是正确的,调用add的时候,传入(1,2)时,返回值却为0,不知什么原因,这个问题困惑了很久,请高手们指教~ 以下是源码 //c#写的webservice的源码 [We ...

  4. axis2 java.net.url_axis2调用.net写的webservice接口实现,指定参数名

    参考文章:https://blog.csdn.net/wangyu2016/article/details/76022928 使用axis2调用调用.net写的webservice接口时出现参数无法传 ...

  5. python文件调用python文件_自己写的python文件如何相互调用

    自己写的python文件如何相互调用?Python中的模块库十分常用,对于常用的模块可以自己动手自定义,但是如何进行调用呢? 模块相互调用 同级目录调用时的两种方法import module prin ...

  6. 浅谈WebService的调用转

    0.前言 前段时间,公司和电信有个合作,产品对接电信的某个平台,使用了WebService接口的调用,实现了业务受理以及单点登录.终于使用到了WebService,楼主还是比较兴奋的,目前功能已经上线 ...

  7. vue 调用webservice_浅谈WebService的调用

    0.前言 前段时间,公司和电信有个合作,产品对接电信的某个平台,使用了WebService接口的调用,实现了业务受理以及单点登录.终于使用到了WebService,楼主还是比较兴奋的,目前功能已经上线 ...

  8. 关于cocos2d-x 和安卓之间的相互调用

    最近在研究cocos2d游戏移植安卓需要调用很多方法,所以在研究之中写下它们之间相互调用 首先,cocos2d调用安卓 在一个.h文件中添加头文件 #include <jni.h> #in ...

  9. iOS架构-多工程联编及framework之间的相互调用(19)

    对于大公司,大工程来说,业务线很多,也时刻在变,功能模块要求能随时下线,或者业务不再需要了,就需要从主工程中移除相关工程或者库.以减小包的大小.多工程联编是一种多业务合作的一种方法. 有篇文章写的很详 ...

最新文章

  1. java kafka分布式_Kafka分布式消息系统
  2. Spring @Scheduled关键字
  3. GridView中超链接HyperLinkField标签的使用方法
  4. 008-SDK框架之LYWSDKPlatformManager.h
  5. 项目管理过程组(5)与知识领域(10)
  6. “宇宙最强”GPU —— NVIDIA Tesla V100 面向开发者开放试用!
  7. Coursera-AndrewNg(吴恩达)机器学习笔记——第一周
  8. contenttype类型_HTTP请求中,几种常见的ContentType类型解析
  9. H5架设新手小白搭建教程(是用于新手)
  10. 百度地图常用的几个webAPI(中文地址转经纬度,经纬度转中文地址)
  11. MySQL8.0 之SQL(DQL)单表、多表查询(详细回顾篇)
  12. 原生js实现可切换式导航栏
  13. 使用SecureCRT时,PageDown键无法使用
  14. win7运行c语言程序,win7打开程序弹出错误0xc000005的解决方法
  15. 工程师排查故障三要诀
  16. 新世代高端旅行六大偏好:Bleisure、场景感、体验感成趋势
  17. 什么是纯函数?使用纯函数有什么好处?
  18. Elasticsearch学习1 入门进阶 Linux系统下操作安装Elasticsearch Kibana 初步检索 SearchAPI Query DSL ki分词库 自定义词库
  19. 毕业论文查重的降重心得
  20. ESLint couldn‘t find the config “standard“ to extend from 解决办法

热门文章

  1. php 递归实现无限极分类和排序_PHP无限级分类实现层级值间用字符串拼接
  2. linux 文件大小_linux系统中查看目录大小的du命令常
  3. 【数学和算法】协方差矩阵、方差
  4. 【目标检测】Faster RCNN算法详解
  5. Caffe学习系列(5):其它常用层及参数
  6. 卷积神经网络(三):卷积神经网络CNN的简单实现(部分Python源码)
  7. Git 基础 - 打标签 tag
  8. 鸟哥的Linux私房菜(服务器)- 第六章、 Linux 网络侦错
  9. 程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]
  10. 数字图像处理:第二十一章 视频压缩标准