LoginSignup
0
0

More than 5 years have passed since last update.

UDP > ASCIIコード以外のunsigned char型変数値の送受信 > 0xE2が化ける問題

Last updated at Posted at 2017-02-23
動作環境
C++ Builder XE4

前置き

UDP通信にて<STX>,<ETX>,<BCC>を含めたコードの送受信を試行している。
フォーマットとしては<STX>ペイロード<ETX><BCC>
http://qiita.com/7of9/items/a91a396f03fac9516814

その際に、<BCC>として計算した値が0xE2などの場合に別のコードに変わってしまうという症状に遭遇している。

関連しそうなのは以下。
http://qiita.com/7of9/items/7bab0cf9f4311f1ebbd1

ASCIIコード
http://www9.plala.or.jp/sgwr-t/c_sub/ascii.html
0x00から0x7Fまで定義されている。

IndyのTidUDPServerなどでコードページ932で受信した時(もしくはchar型変換時)に0x80以降のコードが化けているという状況。

ツールの動作確認

調査の前に、確実に動作するツールを確保しておく。

NonSoftさんのUDP/IPテストツールを使わせていただきます。
http://nonsoft.la.coocan.jp/Download/UdpTool/index.html

AAA<E2>というコードを2つのOS上で送受信してみた。
(以下、0xE2<E2>と記載)
送信側も受信側もUDP/IPテストツールを使用した。

受信側で以下となり、<E2>のコードを含めて送受信は成功している。

接続                (6000 )
->受 192.168.0.31 (4000 )<41><41><41><e2>

以降の動作確認にUDP/IPテストツールを使うことで、不具合の絞込みが可能である。

コードページ932での受信 > 文字化け

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    IdUDPServer1->DefaultPort = 6000;
    IdUDPServer1->Active = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdUDPServer1UDPRead(TIdUDPListenerThread *AThread, const TIdBytes AData,
          TIdSocketHandle *ABinding)
{
    AnsiString rcvdStr;
    Idglobal::_di_IIdTextEncoding encSJIS;

    encSJIS = IndyTextEncoding(932);

    int init_pos = 0;
    rcvdStr = encSJIS->GetString(AData, init_pos, AData.Length);
    int nop=1; // for breakpoint
}
//---------------------------------------------------------------------------

上記のプログラムに対してUDP/IPテストツールからAAA<E2>を送信してみた。

受信文字列は<41><41><41><81>となった。
<E2><81>に化けてしまっている。

対応案

<BCC>の値にはunsigned char型の場合<00>から<FF>の任意の値が入る。<80>以降のコードも受信できるようにするためには、いくつかの対応案が考えられる。

1. すべてをBCDに変換する

<80>の場合、8(<38>)0(<30>)に変換するというBCD(Binary Coded Decimal)表現を使う。
http://qiita.com/7of9/items/c9febc6d0403d8fd6c0e

これにより、送受信される文字列はつねにASCIIコードの値に収まる。
一方で、1バイトの文字を送受信するために2バイトが必要になるため、送受信データサイズが2倍になるという欠点はある。

こちらの方法は使用例をいくつか見たことがある。

2. <BCC>だけをBCDにする

<STX>ペイロード<ETX><BCC>という通信プロトコルの場合、文字化けが発生するのは<BCC>の部分だけ。(<STX><ETX>はASCIIコードのため文字化けしない。)

<BCC>の部分だけをBCDで変換するという案。

送受信データのサイズが抑えられる。

ただし、こちらの方法は標準的な方法ではないかもしれない。
(他の人の使用例を見た記憶がない)。

3. ペイロード,BCC値<CR><LF>にする

<STX>ペイロード<ETX><BCC>のように<STX><ETX>を使うことにこだわらない場合、以下のような形式にするということも考えられる。

ペイロード,<BCC(の数値)><CR><LF>

<BCC><E2>の場合、<E2>はunsigned char型では226になる。以下のようにして送受信するという案。

ペイロード,226<CR><LF>

利点としては、受信側はカンマ区切りでペイロードと<BCC>を分離できる。

欠点としては、<STX><ETX>がないため、送受信文字列の区切りが捉えにくくなる。UDP送受信でこれが問題になるかは未消化。

<CF><LF>終端でカンマ区切り文字列を送受信する例はRS-232C通信などでは多く見てきた。

UDPでは以下の記事内のリンク先に例がある。
http://qiita.com/7of9/items/1c44f6df88733ee586c1

(追記 2017/03/21)
シリアル通信では以下の「Packet type: 220」に1Fのようなchecksumがある。
http://www.pvelectronics.co.uk/PA6B/PA6B_commands.pdf

4. コードページ932以外での送受信にする

ASCIIで受信する限りは文字化けが発生する。
ASCII(コードページ932)以外で受信するという案。

こちらについては調査不足。

1つの<BCC>の文字化け対策のために、関連するコードをすべて変更するのが良い案かは思案中。

他の案

他にも方法があるかもしれない。
それらの方法の選択の視点は「標準的な方法かどうか」。

5. ToHex()を使う案

@rryu さんのコメントをもとに見つけました。

0
0
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0