構造体符号化変換で発生した問題
3243 ワード
使用環境:
ネットワーク通信では,構造体を用いて通信する
構造体の定義は次のとおりです.
クライアント(utf-16符号化):
サーバー側(Linuxシステム、utf-8符号化を採用):
iconv()関数ファミリーを用いてutf-16からutf-8へのコード変換を行う
コードは次のとおりです.
問題が発生:
受信しようとする構造体は全体的に変換されるが,受信時の乱れを招くことが分かった.
デバッグ・コード:
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に変換する
これにより、受信時に合理的に変換できなくなる
解決策:
フィールド毎の符号化変換
コードは次のとおりです.
まとめ:
異なる符号化されたアプリケーション間の通信に遭遇し、メッセージフォーマットの制限がある場合、このような問題が最も発生しやすい.
送信時にも同様の問題が発生します
したがって、utf-8からutf-16クライアントに送信するメッセージを仕様するために、仕様に適合する送信構造体を作成する必要がある.
送信時の変換:
必要な一致構造体:
ネットワーク通信では,構造体を用いて通信する
構造体の定義は次のとおりです.
クライアント(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;
変換コードは受信時の変換と同様であり、フィールド毎の符号化変換が必要である