アプリ版:「スタンプのみでお礼する」機能のリリースについて

プログラミングをしていて詰まったところがあるので教えていただけると幸いです。
開発環境はWindows XPでVisual C++ 2005 です。
シリアル通信において次々と送られてくるデータを1データずつ間違いがないように受信することを考えます。
例えば1つのデータが10バイトからなっていて、そのはじめが
0x10というものだったとすれば、
0x10を検出し、その10個分先の0x10の1つ前までが1データ分となると思います。
これを繰り返して全てのデータを正しく取得したいのですが、プログラムの方法が思い浮かびません。
こんなプログラムの方法はどうか、こんな関数を使ってみてはどうか、などありましたらご教授下さい。
よろしくお願いいたします。

A 回答 (5件)

シリアル通信(データ通信)で避けて通れないのが「同期」と「パケット化」と「エラー判定」と「プロトコルの設計」です。



同期(キャラクタ同期)については、通常、ハードウェアで行うので、ソフトは余り気にしなくて良いのですが、同期ズレは発生した場合、幾つかのバイトが欠落するのをソフト側で考慮しなければなりません。

パケット化は、例えば、データの先頭にマーカー、レングス、連番などを入れ、末尾にチェックサムやCRCを入れるなど、自分でデータ構造を構築しなければなりません。

エラー判定は、パケット単位でデータのチェックサムやCRCを入れ、受け取ったパケットが正常であるか判定しなければなりません。

プロトコルの設計は、データの送受信の双方で、データのやりとりの方法を決め、色々な事象(データ抜け、データ化け、エラー、再送など)に対応した設計をしないとなりません。

質問者さんが考えたように「先頭にレングスだけ」では、もし「先頭のレングスが文字化けした時」や「途中のデータが化けた時」や「途中のデータが抜け落ちた時」に、正しくデータが受信できません。

例えば、以下のような15バイトを、10+5バイトで送出する場合を考えます。

送出データは以下のようになります。
(0A) 01 02 03 04 05 06 07 08 09 10 (05) 11 12 13 14 15
注:()内はレングス

ここで、以下のように先頭が文字化けすると
(08) 01 02 03 04 05 06 07 08 09 10 (05) 11 12 13 14 15

受信側は
(08) 01 02 03 04 05 06 07 08 (09) 10 05 11 12 13 14 15
と解釈し、まず8バイト受け取り、次に9バイト取ろうとしますが、データはいつまで経っても9バイト来ません。永久に待つ事になります。

もし、10が来るまで読み捨ててると、
(08) 01 02 03 04 05 06 07 08 (09)
を捨てて、その先の
(10) 05 11 12 13 14 15
を受け取ろうとしますが、やはり、データは10バイト来ません。永久に待つ事になります。

もし、以下のようにデータの中身が文字化けしたら
(10) 01 12 03 04 05 06 07 08 09 10 (05) 11 12 13 14 15
受信側は02が12に化けたのに気付く事ができません。

なので、パケットの中は「どこが欠落しても、どこが文字化けしても、それが判るようにする必要」があります。

そして「受信パケットがエラーか正常か判定可能」になったら、受信側から送信側に「正常だから次を送れ」とか「エラーだからもう1回送って」などの返答を返す必要が出てきます。

この「受信したらどういう返事をどう返すのかの、取り決め」のが「プロトコル」です。

パケットの設計、エラー判定の設計、プロトコルの設計が出来て、初めて「間違いの起きない送受信」が可能です。

こういうシリアル通信の送受信プロトコルは、既に色々な物が作られているので、そういう資料を見てみるのが良いでしょう。
    • good
    • 0

追記。



実は「LANによるネットワーク通信」も、中身はシリアル通信と同じで、データ抜けやデータ化けが起きています(コリジョンや回線不良)

で、パケット化、エラー訂正は、NIC(ネットワークインターフェースカード)に載っているコントローラLSIが勝手にやってくれます。

あとは、サーバー、クライアントで「プロトコル」を決め、FTPやHTTPやSMTPやPOP3などのサーバーソフト、クライアントソフトが、決められたプロトコル通りにデータを送受信しています。

ですので「確実なシリアル通信の手順」を一から書くのは、ネットワーク階層構造のデータリンク層から上を自分で書くのと同じです(NICのコントローラLSIがやってる様なこと、サーバーソフト、クライアントソフトがやってる様なことを、全部、一から自分で書く、ということ)
    • good
    • 0

> やり方が色々あり、人によって全然違うプログラムになるということ、とかいうことでしょうか?



逆です。
誰がやっても、同じようなプログラムになるうえに、簡単に書けてしまうのでライブラリが用意されていない。

「1から10までの合計を計算して表示しなさい」というプログラムは、いかにも誰でも一度ぐらいは作っていそうですが、これを簡単に実行する関数やライブラリはわざわざ用意されたりしていませんし、仮にあったとしても、わざわざ使ったりしません。どういう言語であれ、おそらくはループ変数を使って足し算していき、最後に出力、という方法になるしかないでしょう。(再帰でもかける、とか、そういう突っ込みはなしです)

今回のご質問もこれと同じです。「とりあえず」であれば、素直にプログラムすればいいだけですから、悩みどころがないのです。
もちろん、実用的なプログラムであればエラー制御などは必須ですし、通信プログラムであれば相手がハングアップやリスタートした時の制御も必要ですから、どんどん複雑になります。が、やはりエラー制御やタイムアウトはライブラリにはなじまないので、自分で作るしかありません。でも、今回はそういう深いレベルの話ではないように思います。
    • good
    • 0

> こんなプログラムの方法はどうか、こんな関数を使ってみてはどうか、などありましたら



ないでしょう。
画期的な関数も思いだしませんし、定番のプログラム方法もないと思います。

というか、「シリアル通信で」という部分をのぞけば、これって、ごく普通のプログラムですよね。こういう形式のファイルはたくさんありますし、そもそも、マシン語ってまさにこれだと思います。ある番地を指定されるとそこから「ひとかたまりの命令」を読み込んで実行し、その次の番地からまたまた「ひとかたまりの命令」を読み込む。「ひとかたまり」の判断は自分で行なうしかない。
それぐらい基本中の基本といってもいいプログラムだと思いますよ。人に質問する前にもっと自分で考えましょう。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
やはりそんなに都合の良いものはありませんか。
正直、実戦的な知識がほとんどない状態で放り込まれたようなものでして、どこに目をつけていいかもよく分からず途方にくれた状態です。
もちろん自分でも考えましたし、調べてもみたのですが・・・
基本中の基本のプログラムでありながら定番のプログラム方法がないとはどういうことでしょうか?
やり方が色々あり、人によって全然違うプログラムになるということ、とかいうことでしょうか?

お礼日時:2008/12/18 01:14

直接の回答ではありませんが…



>0x10を検出し、その10個分先の0x10の1つ前までが1データ分となると思います。

10個…なんですか?
0x10は10進数では16ですが……。
BCD表記なんでしょうか?
    • good
    • 0
この回答へのお礼

1データが10バイトからなっているとしたので、10個と書いたのですが、
自分自身完璧に把握できているわけではないので、もしかしたらおかしなことを言っているかもしれません・・・

お礼日時:2008/12/18 01:07

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!