使用环境:
在网络通信中,使用结构体进行通信
结构体定义如下:
客户端(采用utf-16编码):
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct MsgHead
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public char[] cSenderName;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public char[] cRecverName;
};
服务器端(Linux系统,采用utf-8编码):
typedef struct _MsgHead
{
char cSenderName[16];
char cRecverName[16];
}MsgHead, *pMsgHead;
使用iconv()函数族进行utf-16到utf-8的代码转换
代码如下:
pMsgHead convertToMsgHead(char * recvBuf, int nRecv)
{
CCodeConverter cv=CCodeConverter("utf-16", "utf-8");
//一个占2byte的utf-16字符在utf-8中最多用4byte
int nTransBufSize=2*nRecv;
//作为转换的中介
char * transBuf=new char[nTransBufSize];
memset(transBuf, 0, nTransBufSize);
int nRet=cv.convert(recvBuf, nRecv, transBuf, nTransBufSize);
if(nRet<0)
{
cv.getErrInfo();
return NULL;
}
pMsgHead msgHead;
memcpy(msgHead->cSenderName, transBuf, 16);
memcpy(msgHead->cRecverName, transBuf+16, 16);
//释放转换中介缓存
delete(transBuf);
return msgHead;
}
出现问题:
即将接收到的结构体整体转换过去,但是发现会导致接收的时候紊乱
调试代码,如下所示:
utf-16 |
0 |
2 |
4 |
6 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 | |||
徐 |
薇 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
s |
e | ||||
utf-8 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
徐 |
薇 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
s |
注意:
汉字在utf-16中占2个byte,但在utf-8中占3个byte
问题解析:
把接收到的前4个byte的汉字转换成6个byte之后,其后的28个0,转换为utf-8中的14个0
这样, 导致了接收的时候无法合理的进行转换
解决办法:
逐字段的进行编码转换
代码如下:
pMsgHead convertToMsgHead(char * recvBuf, int nRecv)
{
CCodeConverter cv=CCodeConverter("utf-16", "utf-8");
//一个占2byte的utf-16字符在utf-8中最多用4byte
int nTransBufSize=2*nRecv;
//作为转换的中介
char * transBuf=new char[nTransBufSize];
memset(transBuf, 0, nTransBufSize);
pMsgHead msgHead;
//转换字段cSenderName
cv.convert(recvBuf, 32, transBuf, nTransBufSize);
memcpy(msgHead->cSenderName, transBuf, 16);
//转换字段cRecverName
cv.convert(recvBuf+32, 32, transBuf, nTransBufSize);
memcpy(msgHead->cRecverName, transBuf+16, 16);
//释放转换中介缓存
delete(transBuf);
return msgHead;
}
小结:
碰到不同编码的应用程序之间通信,而且有消息格式的限制时,最容易出现这种问题
在发送的时候也会出现类似的问题
因此,需要创建一个符合规范的发送结构体来对从utf-8要发送到utf-16客户端的消息进行规范
发送时的转换:
需要用到的匹配结构体:
typedef struct _CommMsgHead
{
char cSenderName[32];
char cRecverName[32];
}CommMsgHead, *pCommMsgHead;
转换代码则与接收时的转换类似,需要逐字段进行编码转换