今回初めてIndyを使ってみました。
(今まで、Delphi5の時代ではScktCompでchatを使ってみたりしてました)
「ソケットライブラリのIndyを利用したクリップボード共有ソフト」
https://codezine.jp/article/detail/197 を参考に、
単純な送受信アプリを作ってみたのですが、日本語が文字化けが発生しました。
動作環境は、クライアント、サーバー共にWindows10Pro64bitです。
(将来はクライアントをandroidに、と思ってます)
開発は、Delphi 10.3.3 Community Edition Indy:10.6.2.5366 です。
[クライアント]
procedure TForm1.Button1Click(Sender: TObject);
begin
IdTCPClient1.IOHandler.Write((Edit1.Text)+#13#10);
end;
[クライアントスレッド]
procedure TTcpListenerThread.Execute;
var
Bytes: TIdBytes;
RecvData: string;
begin
while not Terminated do
begin
if not Form1.IdTCPClient1.Connected then
begin
Terminate;
Continue;
end;
RecvData := Form1.IdTCPClient1.IOHandler.ReadLn(#13#10);
// Synchronize(SyncPrint);
Form1.Memo1.Lines.Add(RecvData);
end;
end;
[サーバー側]
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
S: String;
Bytes: TIdBytes;
begin
S := AContext.Connection.IOHandler.ReadLn(#13#10);
Memo1.Lines.Add(S);
AContext.Connection.IOHandler.Write(S+#13#10);
end;
Edit1.Textに日本語を設定してみたのですが文字化けしてしまいます。
色々、ググって探しているのですが、結果が得られません。
「Delphi 素朴なソケット通信をしたい - Qiita」(https://qiita.com/himajin_sekky/items/ffd5c5c854328287ed2d )や、
UDPの文字化け対策をこの掲示板で拝見し、TEncodingを使ってみたり試行錯誤してみたのですが、解決しませんでした。
Indyの決まり事を私が知らないだけのような気がします。
勉強不足で申し訳ございません。
よろしくお願いいたします。
参考にしたサイトにほとんど答えがあるような・・・
参考したサイトから抜粋
>>汎用のソケット通信ツールを使用して、接続したり、文字を送ってみてください。
これ Shift-JISで作られてますね。
>>今回は、TEncoding のインスタンスをFormCreate内で作成しています。
>>コードページには、932(Microsoft コードページ Shift-JIS)を指定します。
Shift-JISとして送信して Shift-JISとして受信するので文字は化けません。
で、デンカさんのソース
IdTCPClient1.IOHandler.Write((Edit1.Text)+#13#10);
これだと UTF-8で送信して Shift-JISに変換になるのかな?
なので同じ文字コードになるように変換が必要です。
takeさん、ありがとうございます。
間違っている解釈だと思いますが、確認させてください。
(低レベルですみません)
IdTCPClient1.IOHandler.Write((Edit1.Text)+#13#10);
ここでUTF-8で送信しているとのことですが、
サーバー側では、受信したデータを何も変更(コード変換など)せずにクライアントへ送信しています。
(サーバー側のmemo1追加箇所は無視してください)
これをクライアントスレッドで受信したデータもUTF-8でしょうか?
だとすると、受信した(私のソースですと)RecvDataをShift-JISに変換してmemo1に追加すれば
良いかと考えて、参考ページを拝借して、
RecvData := Form1.IdTCPClient1.IOHandler.ReadLn(#13#10);
の部分を以下のように変更してみました。
FEncoding:TEncoding;
FEncoding := TEncoding.GetEncoding(932);
Form1.IdTCPClient1.IOHandler.ReadBytes(Bytes,-1);
RecvData := TEncoding.Unicode.GetString(Bytes);
Form1.Memo1.Lines.Add(RecvData);
ダメデシタ。。。
基本的な考えが間違っていると思います。
お手数をおかけしますが、ご教授よろしくお願いいたします。
数十年ぶりに Indyを使ってみました
IdTCPClient1.IOHandler.Write('漢字'+#13#10)
Indyを使って '漢字' #13#10 を送信したところ
3F 3F D A
という4バイトが送信されたので送信のときにデータが崩れていますね
Writeが漢字に対応していないのでその前に変換が必要そうです。
var
s1,s2 : string;
Bytes: TIdBytes;
begin
s := '漢字'+#13#10;
Bytes := FEncoding.GetBytes(s);
IdTCPClient1.IOHandler.WriteDirect(Bytes);
これで正常に送信出来て受信も出来ましたがどうでしょうか?
takeさん、ありがとうございます。
修正してみたのですが、この行で以下のコンパイルエラーになってしまいます。(s : string; は修正済)
Bytes := FEncoding.GetBytes(s);
[dcc64 エラー] Unit1.pas(51): E2010 'TIdBytes' と 'System.TArray<System.Byte>' には互換性がありません
takeさんの環境では動作して、私のではコンパイルエラーとは?
あれれ?
試した環境はDelphiXE2とIndy Rev 1.123
出たエラーを検索したところ DelphiXE4付属のIndyから仕様が変わったようです。
送信の方は文字化けが直りました。
Encodingを使わず IOHandlerのDefStringEncoding を変更してから送信
IdTCPClient1.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
IdTCPClient1.IOHandler.Write(s);
または受信の方と同じやり方で
送信する所で encoding : IIdTextEncoding; を定義
encoding := IndyTextEncoding_UTF8;
IdTCPClient1.IOHandler.Write(s,encoding);
受信の方は
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
Text: String;
encoding : IIdTextEncoding;
begin
encoding := IndyTextEncoding_UTF8;
Text:= AContext.Connection.IOHandler.ReadLn(#13#10,encoding);
Memo1.Lines.Add(Text);
AContext.Connection.IOHandler.Write('OK');
end;
簡単なようなややっこしいような・・・
やっぱりあんまりIndyは使いたくないな
takeさん、ありがとうございました。
なんとか文字化けしないで表示できるようになりました。
微調整が必要ですが・・・
>やっぱりあんまりIndyは使いたくないな
Delphi10.3CEのマルチデバイス開発(目的はWindowsとAndroid間)で、ソケットのお勧めがありましたら紹介してください。
うまくいったようで何よりです。
マルチデバイス開発対応のソケット通信は Indyしか無いと思います。
当時Delphi3だか5だかでDelphi製のソケット通信もあったと記憶しています。
※Twebbrowser クラス付近にあったような
その後、別インストールが必要ですが Indyが出て
その実験中に質問と同じく漢字(EUCコード)が送受信出来ず
仕方なく自主開発のソケット通信でなんとかやってきてます。
Indy含めてソケット通信に関してはもっと資料が出ていてもおかしくないのですが未だに無いですね。
Delphi5のときにscktcompのTCustomWinSocketを使ってました。
色々ありがとうございました。