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时,会提示没用执行方法(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相互调用相关推荐
- python模块--如何相互调用自己写的模块
一.模块相互调用同级目录调用时的两种方法 1 import module 2 print(module.add(3,8)) 3 4 from module import add 5 print(add ...
- android wsdl封装,在Android中调用C#写的WebService(附源代码)
由于项目中要使用Android调用C#写的WebService,于是便有了这篇文章.在学习的过程中,发现在C#中直接调用WebService方便得多,直接添加一个引用,便可以直接使用将WebServi ...
- delphi 调用 c# 写的webservice
调用helloWorld的返回值是正确的,调用add的时候,传入(1,2)时,返回值却为0,不知什么原因,这个问题困惑了很久,请高手们指教~ 以下是源码 //c#写的webservice的源码 [We ...
- axis2 java.net.url_axis2调用.net写的webservice接口实现,指定参数名
参考文章:https://blog.csdn.net/wangyu2016/article/details/76022928 使用axis2调用调用.net写的webservice接口时出现参数无法传 ...
- python文件调用python文件_自己写的python文件如何相互调用
自己写的python文件如何相互调用?Python中的模块库十分常用,对于常用的模块可以自己动手自定义,但是如何进行调用呢? 模块相互调用 同级目录调用时的两种方法import module prin ...
- 浅谈WebService的调用转
0.前言 前段时间,公司和电信有个合作,产品对接电信的某个平台,使用了WebService接口的调用,实现了业务受理以及单点登录.终于使用到了WebService,楼主还是比较兴奋的,目前功能已经上线 ...
- vue 调用webservice_浅谈WebService的调用
0.前言 前段时间,公司和电信有个合作,产品对接电信的某个平台,使用了WebService接口的调用,实现了业务受理以及单点登录.终于使用到了WebService,楼主还是比较兴奋的,目前功能已经上线 ...
- 关于cocos2d-x 和安卓之间的相互调用
最近在研究cocos2d游戏移植安卓需要调用很多方法,所以在研究之中写下它们之间相互调用 首先,cocos2d调用安卓 在一个.h文件中添加头文件 #include <jni.h> #in ...
- iOS架构-多工程联编及framework之间的相互调用(19)
对于大公司,大工程来说,业务线很多,也时刻在变,功能模块要求能随时下线,或者业务不再需要了,就需要从主工程中移除相关工程或者库.以减小包的大小.多工程联编是一种多业务合作的一种方法. 有篇文章写的很详 ...
最新文章
- java kafka分布式_Kafka分布式消息系统
- Spring @Scheduled关键字
- GridView中超链接HyperLinkField标签的使用方法
- 008-SDK框架之LYWSDKPlatformManager.h
- 项目管理过程组(5)与知识领域(10)
- “宇宙最强”GPU —— NVIDIA Tesla V100 面向开发者开放试用!
- Coursera-AndrewNg(吴恩达)机器学习笔记——第一周
- contenttype类型_HTTP请求中,几种常见的ContentType类型解析
- H5架设新手小白搭建教程(是用于新手)
- 百度地图常用的几个webAPI(中文地址转经纬度,经纬度转中文地址)
- MySQL8.0 之SQL(DQL)单表、多表查询(详细回顾篇)
- 原生js实现可切换式导航栏
- 使用SecureCRT时,PageDown键无法使用
- win7运行c语言程序,win7打开程序弹出错误0xc000005的解决方法
- 工程师排查故障三要诀
- 新世代高端旅行六大偏好:Bleisure、场景感、体验感成趋势
- 什么是纯函数?使用纯函数有什么好处?
- Elasticsearch学习1 入门进阶 Linux系统下操作安装Elasticsearch Kibana 初步检索 SearchAPI Query DSL ki分词库 自定义词库
- 毕业论文查重的降重心得
- ESLint couldn‘t find the config “standard“ to extend from 解决办法
热门文章
- php 递归实现无限极分类和排序_PHP无限级分类实现层级值间用字符串拼接
- linux 文件大小_linux系统中查看目录大小的du命令常
- 【数学和算法】协方差矩阵、方差
- 【目标检测】Faster RCNN算法详解
- Caffe学习系列(5):其它常用层及参数
- 卷积神经网络(三):卷积神经网络CNN的简单实现(部分Python源码)
- Git 基础 - 打标签 tag
- 鸟哥的Linux私房菜(服务器)- 第六章、 Linux 网络侦错
- 程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]
- 数字图像处理:第二十一章 视频压缩标准