使用环境:
在网络通信中,使用结构体进行通信
结构体定义如下:
客户端(采用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;
转换代码则与接收时的转换类似,需要逐字段进行编码转换