|
现象:
使用ICE做开发,C++的服务端,C#的客户端,如果返回的string参数中包含有中文,则C#客户端会抛异常。异常如下:
Ice.MarshalException reason
=
"
Invalid UTF8 string
"
在 IceInternal.ProxyFactory.checkRetryAfterException(LocalException ex, Reference
ref
, OutgoingAsync outAsync, Int32
&
cnt) 位置 d:\builds\distbuilds\release\Ice
-
3.3
.
0
\cs\src\Ice\ProxyFactory.cs:行号
183
在 Ice.ObjectPrxHelperBase.handleException__(ObjectDel_
delegate
, LocalException ex, OutgoingAsync outAsync, Int32
&
cnt) 位置 d:\builds\distbuilds\release\Ice
-
3.3
.
0
\cs\src\Ice\Proxy.cs:行号
880
在 Ice.ObjectPrxHelperBase.handleExceptionWrapperRelaxed__(ObjectDel_
delegate
, LocalExceptionWrapper ex, OutgoingAsync outAsync, Int32
&
cnt) 位置 d:\builds\distbuilds\release\Ice
-
3.3
.
0
\cs\src\Ice\Proxy.cs:行号
919
在 Demo.DemoIcePrxHelper.GetEx(String
&
strMsg, Dictionary`
2
context__, Boolean explicitContext__) 位置 E:\Workspace\VC
++
\Test\IceVC8\DemoIce\DemoC_cs\DemoC_cs\DemoIce.cs:行号
95
在 Demo.DemoIcePrxHelper.GetEx(String
&
strMsg) 位置 E:\Workspace\VC
++
\Test\IceVC8\DemoIce\DemoC_cs\DemoC_cs\DemoIce.cs:行号
67
在 IceClientCon.Program.Main(String[] args) 位置 E:\Workspace\VC
++
\Test\IceVC8\DemoIce\DemoC_cs\DemoC_cs\Program.cs:行号
24
Caused by: System.Text.DecoderFallbackException: 无法将位于索引
1
处的字节 [BA] 由指定的代码页转换为 Unicode。 在 System.Text.DecoderExceptionFallbackBuffer.Throw(Byte[] bytesUnknown, Int32 index) 在 System.Text.DecoderExceptionFallbackBuffer.Fallback(Byte[] bytesUnknown, Int32 index) 在 System.Text.DecoderFallbackBuffer.InternalFallback(Byte[] bytes, Byte
*
pBytes) 在 System.Text.UTF8Encoding.FallbackInvalidByteSequence(Byte
*
pSrc, Int32 ch, DecoderFallbackBuffer fallback) 在 System.Text.UTF8Encoding.GetCharCount(Byte
*
bytes, Int32 count, DecoderNLS baseDecoder) 在 System.String.CreateStringFromEncoding(Byte
*
bytes, Int32 byteLength, Encoding encoding) 在 System.Text.UTF8Encoding.GetString(Byte[] bytes, Int32 index, Int32 count) 在 IceInternal.BasicStream.readString() 位置 d:\builds\distbuilds\release\Ice
-
3.3
.
0
\cs\src\Ice\BasicStream.cs:行号
1810
于是我做了四组实验,分别返回中文string类型的参数到客户端,结果如下: C++服务端 C# 客户端 异常 C++服务端 C++客户端 正常 C# 服务端 C# 客户端 正常 C# 服务端 C++客户端 乱码
分析原因: c++下的string使用的是ASCII码,而c#的string使用的是unicode编码,查看ICE文档,发现ICE传输的时候使用的是UTF-8,我把ASCLL的string当做utf-8格式的string发送给C#客户端,C#客户端解码这种格式的时候当然出问题了。
解决问题:
解决方法有二种:1、通过传输字节流来代替string. 2、将C++服务端的ASCLL的编码sting 转换成utf-8编码的string再传输,使客户端服务端编码格式统一。
解决方法1:
通过传输字节流来代替string. ICE 部分代码:
sequence
<
byte
>
ByteSeq; idempotent
void
Test(
out
ByteSeq strOutValue);
c++服务端部分代码:
void
CUserRequestI::Test(ByteSeq
&
byteSeq,
const
::Ice::Current
&
ice)
{
string
strValue
=
"
AB汉字没关系。
"
; printf(
"
Test.In=%s\n
"
,strIn.c_str());
int
i
=
0
;
for
( i
=
0
; i
<
strValue.length(); i
++
)
{ byteSeq.push_back(strValue.c_str()[i] ); }
printf(
"
Test push=%d\n
"
,i); }
C#客户端部分代码:
private
void
Test()
{
byte
[] strValue; userRequestPrx.Test(
out
strValue);
//
调用ICE接口
Encoding CnEnconding
=
Encoding.GetEncoding(
"
GB18030
"
);
//
GB2312
string
str
=
CnEnconding.GetString(strValue); Console.WriteLine(
"
getStr={0}
"
,str);
//
输出正常的string
}
解决方法2:
将C++服务端的ASCLL的编码格式sting转换成utf-8格式的string再发送
ICE文件 DemoIce.ice
C++服务端代码: //File: DemoS.cpp
//http://www.cnweblog.com/fly2700/
#include
<
stdio.h
>
#include
<
Ice
/
Ice.h
>
#include
<
DemoIce.h
>
#include
<
Windows.h
>
using
namespace
Demo;
using
namespace
std;
void
unicodeToUTF8(
const
wstring
&
src,
string
&
result)
{
int
n
=
WideCharToMultiByte( CP_UTF8,
0
, src.c_str(),
-
1
,
0
,
0
,
0
,
0
); result.resize(n); ::WideCharToMultiByte( CP_UTF8,
0
, src.c_str(),
-
1
, (
char
*
)result.c_str(), result.length(),
0
,
0
); }
void
unicodeToGB2312(
const
wstring
&
wstr ,
string
&
result)
{
int
n
=
WideCharToMultiByte( CP_ACP,
0
, wstr.c_str(),
-
1
,
0
,
0
,
0
,
0
); result.resize(n); ::WideCharToMultiByte(CP_ACP,
0
, wstr.c_str(),
-
1
, (
char
*
)result.c_str(), n,
0
,
0
); }
void
utf8ToUnicode(
const
string
&
src, wstring
&
result)
{
int
n
=
MultiByteToWideChar( CP_UTF8,
0
, src.c_str(),
-
1
, NULL,
0
); result.resize(n); ::MultiByteToWideChar( CP_UTF8,
0
, src.c_str(),
-
1
, (LPWSTR)result.c_str(), result.length()); }
void
gb2312ToUnicode(
const
string
&
src, wstring
&
result)
{
int
n
=
MultiByteToWideChar( CP_ACP,
0
, src.c_str(),
-
1
, NULL,
0
); result.resize(n); ::MultiByteToWideChar( CP_ACP,
0
, src.c_str(),
-
1
, (LPWSTR)result.c_str(), result.length()); }
class
DemoIceI :
public
Demo::DemoIce
{
public
:
virtual
void
SetEx(
const
::std::
string
&
param,
const
::Ice::Current
&
)
{
string
strData; wstring strUnicode; utf8ToUnicode(param,strUnicode); unicodeToGB2312(strUnicode, strData); printf(
"
SetEx().called,UTF-8 code=%s \t gb2312=%s\n
"
,param.c_str(), strData.c_str()); }
virtual
void
GetEx(::std::
string
&
param,
const
::Ice::Current
&
)
const
{
string
strGB2312
=
"
AB汉字接受
"
; wstring wstrUnicode;
string
strUTF8; gb2312ToUnicode(strGB2312,wstrUnicode); unicodeToUTF8(wstrUnicode,param); printf(
"
GetEx().called,UTF-8 code=%s \t gb2312=%s\n
"
,param.c_str(), strGB2312.c_str()); }
}
;
int
main()
{
/**/
////////////////////////////////////////////////////////////////////////
//
int
status
=
0
; Ice::CommunicatorPtr ic;
try
{ ic
=
Ice::initialize(); Ice::ObjectAdapterPtr adapter
=
ic
->
createObjectAdapterWithEndpoints(
"
DemoIceEndpoint
"
,
"
default -p 10000
"
); Demo::DemoIcePtr demoIcePtr
=
new
DemoIceI(); adapter
->
add(demoIcePtr, ic
->
stringToIdentity(
"
DemoIce
"
)); adapter
->
activate(); printf(
"
server.start ok \n
"
); ic
->
waitForShutdown(); }
catch
(
const
Ice::Exception
&
ex)
{ cerr
<<
ex
<<
endl; status
=
1
; }
catch
(
const
char
*
msg)
{ cerr
<<
msg
<<
endl; status
=
1
; }
if
(ic)
{ ic
->
destroy(); }
return
status; }
C#客户端代码: //File Program.cs
using
System;
using
System.Collections.Generic;
using
System.Text;
using
Demo;
namespace
IceClientCon
{
class
Program
{
public
static
void
Main(
string
[] args)
{
int
status
=
0
; Ice.Communicator ic
=
null
;
try
{ ic
=
Ice.Util.initialize(
ref
args); Ice.ObjectPrx obj
=
ic.stringToProxy(
"
DemoIce:tcp -h 127.0.0.1 -p 10000
"
).ice_twoway().ice_timeout(
200
).ice_secure(
false
); DemoIcePrx demoIce
=
DemoIcePrxHelper.checkedCast(obj);
if
(demoIce
==
null
)
throw
new
ApplicationException(
"
Invalid proxy
"
);
string
strSetValue
=
"
AB汉字发送
"
;
string
strGetValue
=
""
; demoIce.SetEx(strSetValue); demoIce.GetEx(
out
strGetValue); Console.WriteLine(
"
Set={0},Get={1}
"
, strSetValue, strGetValue); }
catch
(Exception e)
{
string
strErr
=
e.ToString(); Console.Error.WriteLine(e); status
=
1
; }
Console.ReadLine();
if
(ic
!=
null
)
{
try
{ ic.destroy(); }
catch
(Exception e)
{ Console.Error.WriteLine(e); status
=
1
; }
}
if
(status
!=
0
)
{ System.Environment.Exit(status); }
}
}
}
|