今までソケット通信は、プロジェクトの設定を「マルチバイト」にて作業して
いましたが、WindowsCE機での開発を行う事になり、CEはユニコードでないと
ならない様でプロジェクトをユニコードに設定してテストを開始しましが、
以下の様にユニコードとマルチバイトの変換を行わないと正しく送れませんでした。
クライアント側(CE)
環境:eMbedded Visual C++ 4.0(MFC)
CSocket Sock;
AfxSocketInit();
Sock.Connect(_T(IPアドレス), ポート番号);
const TCHAR stzTBuff[] = _T(1234567890);
char stzBuff[32];
// マルチバイトに変換
WideCharToMultiByte(CP_ACP,0,stzTBuff,-1,stzBuff,sizeof(stzBuff),NULL,NULL);
int iSlen = 0;
while ( iSlen != _tcslen(stzBuff) )
{
// _tcslen(stzBuff)は10を返す
iSlen += Sock.Send(&stzBuff[iSlen],_tcslen(stzBuff) - iSlen,0);
}
AfxMessageBox(_T(サーバーへ送信 成功!));
Sock.Close();
サーバー側(WinXP SP2)
環境:VS2005(MFC)
CSocket iniSock;
CSocket RecvSock;
AfxSocketInit();
iniSock.Create(ポート番号);
iniSock.Listen(1);
iniSock.Accept(RecvSock);
char stzBuff[64];
int Rlen = 0;
while( Rlen != 10 )
{
Rlen += RecvSock.Receive(&stzBuff[Rlen],10 - Rlen,0);
}
stzBuff[Rlen] = '\0';
TCHAR stzTBuff[128];
// ユニコードに変換
MultiByteToWideChar(CP_ACP,0,stzBuff,-1,stzTBuff,sieof(stzTBuff));
AfxMessageBox(stzTBuff); // 1234567890と表示される
RecvSock.Close();
iniSock.Close();
そもそもユニコードとマルチバイトの変換を行わないといけないものなのでしょう
か?。
(SendやReceive関数はユニコード非対応関数?)
何卒ご教授願います。
何か大きく勘違いしているような気がするが・・・
プログラム内部の文字コード表現と、プログラムの外での文字表現を混乱しているな
別プログラム=既存のサーバー上のdaemonソフト、が受け付ける文字コードは
「そのdaemonの外部仕様書」にて決められているはずだよ
その仕様書に ASCII と書かれているなら、自作ソフトでで勝手に UTF16 を送っても
サーバー側 daemon が受け付けるわけがないよな
> (SendやReceive関数はユニコード非対応関数?)
というよりは文字コード表現など一切無関係な関数というべきだ。
バイナリ値を送受信するためのものなので勝手にコード変換などされては困る。
> ユニコードとマルチバイトの変換を行わないといけないものなのでしょうか?
まあそういうことになるかな。
daemon 側が UTF16 をも受け付けてくれるのであれば変換不要というべきかな。
その辺はいろいろすべて、仕様次第
別の致命的バグがあるんだけど気づいているかい?
CEでUNICODEで扱わないといけないのは表示がUNICODEでしか出来ないからです。
プログラム内部ではマルチバイトコードで保持していても別に問題ないはずです。
表示する時にUNICODE変換すれば、問題なく出来ますよね。
まあ、文字列として扱う場合には要注意になりますけれど。
問題があるとすれば、マルチバイトコードで保持しているデータをUNICODEを
期待している関数にそのまま渡してしまうようなケースでしょう。
サーバー側のプログラムに関して受け側がマルチバイトでプロジェクトを
作成しているなら受け取った後、文字列として処理する時にうまくいかなくても
不思議ではないですよね。
デバッガ上ではマルチバイト文字として表示しようとするでしょうし。
その辺もふまえて旨く通信が出来なかった事をどうやって確認しましたか?
ご回答有難うございます。
今回、クライアントのCE機からサーバーPC(XP)へデータ要求に行き、
サーバーPCがデータベースを検索した結果をCEへ返し、一部のデータを
表示する仕様となっています。
tetrapodさんへ
>別の致命的バグがあるんだけど気づいているかい?
今後の為にお教え下さい。m(__)m
PATIOさんへ
>その辺もふまえて旨く通信が出来なかった事をどうやって確認しましたか?
クライアントからの送信で
iSlen += Sock.Send(&stzTBuff[iSlen],_tcslen(stzBuff) - iSlen,0);
^^^^^^^^
とTCHAR型を送信元にしてして送って、
サーバー側で
Rlen += RecvSock.Receive(&stzTBuff[Rlen],10 - Rlen,0);
^^^^^^^^
として受けると表示が12345?????(?は読めない漢字)になってました。
ユニコードだからと送信文字数を2倍、受け取りも2倍の20にしてみましたが
やはりおかしな表示となりました。
お話を伺っているとサーバーも含めて内部はマルチバイトで持ってCE機に表示
するときにユニコードに変換が良いかなと思っております。
MultiByteToWideChar の最後の引数は「文字数」であって「バイト数」ではないのだ
無造作に sizeof (提示コードではスペルが違っているな・・・) を渡すと
バッファオーバーフローで困るよ (今のコードではたまたま起こらないけど)
MB/WC 系の関数に渡すバッファサイズはたいてい文字数なので注意。
バイトオーダーまでみな含めて TCHAR を直接送受信するのは仕様として正しくない
と思われる。ネットワークバイトオーダーなんてのも歴史的に決まってるし・・・
サーバーの仕様は変わってなのだから、今まで通り
(多分)ASCII(=MBC)で通信するのでしょう。
これは、tetrapod さんPATIOさんが指摘されている通りです。
従って、送受信の所は明確に(多分)ASCIIでやり取りしなくては
なりません。
例えば、ファイル出力があり、その仕様がASCIIで
あればそうしなければならないですよね。
ただ、画面にTextOutするとき等にはUnicodeしか渡せない
ということです。
サ-バ側のOSはなんですか?
通信の基本は
「文字コ-ド、通信仕様等は極力サーバ-にあわせる。」
どです。
漢字を使わずにANSI英数字のみで文字化けしないか確かめましたか?
文字が途中で切れてませんか?
今までの流れからすると確認してあるようにみえますが実際はどうですか。
追記
サ-バ側のOSがWindowsXP等でもともとサーバーでないのなら、
Unicodeで通信できるか探ることも可能かもしれませんね。
Framework等であるかもしれませんね。
存知のかたお願いします。
おはようございます。
tetrapodさんへ
不具合ご指摘有難う御座います。
仲澤@失業者さんへ
送受信はご指摘の通りASCIIで作成と考えています。
CE機は受信したデータを一旦ファイルに書き込む予定なので
書き込み、読み込み時に変換しようと思います。
ITOさんへ
私がサーバーと呼んでいるのは、ソケット通信上サーバープログラム
になっている為で、実際は普通のWinXP機です。
このサーバー機側のプログラムも自前で作成しますので仕様は自由です。
内部処理ASCIIにて作成と思っています。
> 私がサーバーと呼んでいるのは、ソケット通信上サーバープログラム
> になっている為で、実際は普通のWinXP機です。
うーーん
同じWinXPどうしならなんかいい方法があるかと思うのですが.....
しかし、CSocketで作ってあれば相手のサーバがUNIX等になっても
対応できると思うので、ASCII→Unicodeの変換がうまくいくならば
現状の方法がベストだと思います。
みなさんのお話を伺い、コード変換で行こうと思います。
ご意見有難う御座いました。
解決とさせて頂きます。