RS-232C Unicode(ユニコード)の壁 | |
|
文字送信に関する一般的な問題点
ユニコードに関して説明する前に、RS-232Cで文字の送受信をする場合の問題点を説明する。
RS-232Cの通信はデータの垂れ流し通信である。 つまり送受信の開始は有っても終了は無いので有る。 そしてこれは文字の送受信の場合困った状態を引き起こす。 漢字コードの泣き別れ
例えば仮に2台のコンピューターでRS-232Cのチャットのプログラムを作成したとしよう。
送信側は何らかのメッセージを書き込んで送信ボタンを押したと仮定する。 受信側は送られた文字列をテキストボックスに書き込んで表示するのである。 通常serialPortクラスのReceivedBytesThresholdは1に設定されており、1文字が受信されると 受信イベントが起きる。 起きたイベントで受信文字を取得するので有るが、この場合1文字を取得するとは限らない。 なぜならイベントが起きた時間と文字を取得するまでの時間にタイムラグが有る為、 其のタイムラグの時間内に更なる受信が行なわれるからである。 仮に送信側が "長安一片の月 万戸砧を打つの声" と送信したとしよう、受信側の最初の受信は"長安一片"となるか "長安"となるか 又は送られた全ての文字を取得で出来るかは未定で有る。 もし読める文字で取得出来たらそれはラッキーである、なぜならどの様なエンコード方式を使っても 漢字は2バイト以上で表されるから、受信文字の最後が調度漢字文字の区切りのバイトになるとは限らないのである。 つまりかなりの確立で漢字のバイトが完結しない言わば泣き別れになる可能性が有るのだ。 serialPortクラスにはReadExistingというメソドが有って、これは漢字の区切りでデータを読み込み区切りの悪いところは バッファに残すようであるが、今ひとつ使いにくい。 そもそもバイト配列で受信しようとする場合はどうしたら良いのだろうか。 時間で判断する方法
送信側が有る文字を書き込んで送信ボタンを押し、次の新しい文字を書き込んで送信ボタンを押す。
この送信ボタンを押してから次の送信ボタンを押すまでのタイムラグを利用する方法である。 受信側は受信イベントが起きると文字を取得し配列に入れる、ただし表示しないでここでタイマーを設定する。 タイマーのタイムアップが来ない内に次の受信イベントが起きたら、更に配列に文字を追加してタイマーを再設定する。 そしてタイマーがタイムアップした時点で初めて文字を表示するのである。 この方法はかなり実用的な方法で有る、タイマーは100msec位を設定すれば良く、殆ど遅れは気にならない。 改行文字を区切りとする方法
タイマーの方法で気になるのは長い文章を送ってそれを受信側で順次表示する方法で有る。
この場合は全ての文字を受信しなければ表示されない可能性が有る。 そこで登場するのが改行を区切るとして表示する方法である。 受信側はひたすら改行文字の受信を待って改行文字が来た時点で表示を行なう方法である。 この方式は必ず少なくても送信文字の最後は改行で終わらなくてはならない。 そして注意する点は文字エンコードの方式により改行のコードが異なる点である。
Unicode(ユニコード)を克服せよ
VB6は内部処理は全てユニコードであったが、表示やファイル処理、外部とのやり取りは全てSift-Jisで有った。
VB.NET、C#は全てユニコード処理である。 しかも厄介なことに、Frameworkは特に指定しない限る、文字列のstreamはUTF-8を吐き出す。 従ってVB.NET、C#でSystem.IO.Ports.SerialPortクラスを使用してRS-232Cの文字の送受信を行う場合は 次の点に留意する必要がある。 VB.NET、C#ではテキストは全てユニコードで処理されるが、コンピューター対コンピューターの接続を除けば、 RS-232Cが接続される従来の機器のほとんどは通信はShift-Jisで行われる。 従って従来の機器との接続をする場合は、コンピューター側からは送信時はユニコードからShift-Jisに、 受信時はShift-Jisからユニコードへ変換する必要が生じるのである。 幸い.net Framework にはEncodingクラスと言うクラスが有って、文字コード間の変換は比較的容易に行うことが出来る。 もちろん文字コードを自由に変えられる仕様にしておくことが一番であるが、この場合常に使用する側が正しく設定する必要がある。 文字コードを選択して送る方法は 「C#,VB2005 RS-232C 送信モジュール」 に書いています。 ところで相手が一体何の文字コードでデータを送って来ているのか知りたい場合が有ります。 「C#,VB2005でRS-232CのHEXモニタ 」 に受信データをHEXで表示するモニタの作成方法を載せておきました。 これでデータを表示して、 「Unicode 入門 (C#,VB.NET)」 で何のコードが送られて来たか調べてみて下さい。
送信サンプルコード
下に送信コードのサンプルを示します、この関数は送信したいデーターの文字列を引数として渡すと、
その文字列から、shift-jisの配列を作成し、バイトと配列の状態で、送信バッファに書き込みます。 送信が成功すると、Trueを失敗するとFalseを返します。
VB2005のコード
'文字の送信
上の例では送信文字は、SerialPort1.Write(byteArray, 0, byteArray.Length)とバイト配列で送っている。
これを文字列で送るにはどうしたら良いのだろうか。 実はこのEncodingクラスにはGetStringというメソドが有って、バイトアレイを簡単に文字列に変換してくれる。
VB2005のコード
Dim strSend As String = encSjis.GetString(byteArray)
これがバイト配列から文字列に書き換えたサンプルである。
VB.NETを使えば、Shift-Jisだろうが、Unicodeだろうが怖いものは無いのである。 (注意) ここにはVB2005のコードのみ示していますがC#のコードは 「C#,VB2005 RS-232C 送信モジュール」 を参考にしてください。 |