如下宏文(原文在 http://blog.sina.com.cn/s/blog_4e7d38260100ade4.html),是转贴并进行了修饰编辑: php
首先感谢永和兄提供C++的WebService服务器端及客户端,而且陪我一块儿熬夜;而后是火石和我作接口的兄弟,虽然都不知道你叫什么,若是没有你的合做,东西也没那么快完成。 html
1、因为公司运营火石的《西游Q记》,火石采用的是C++做为开发语言,Unix平台,而咱们一直使用Windows操做平台,.NET快速开发。咱们之间须要数据的通信,因此须要利用WebService实现跨平台的数据通信。尽管WebService是跨平台的,可是实现起来却并不容易。
6、开始解决问题。做为.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++繁琐,语言既然存在则有他的价值。
======================= 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++