Part1 通信プロトコルとは

最終更新: 1998-10-02

1.1 BBSの始まり

BBS(電子掲示板)は、多くの利用者が読めるように公開されたという意味において、確かに駅にある伝言板と同じように、掲示板としての用途に適している。しかし、BBSの利用者はパソコンを使うことができたので、文書以外のデータ、プログラムもやりとりしたいという要求がただちに発生した。

テキストの場合には、データに現れる文字が限られており、特にアスキー文字の場合には、0x00〜0x1fに相当する文字はコントロール文字とみなされ、文意を伝達するための、いわゆる通常の文字とは異なった意味を持つ。文章中に現れるコントロール文字もある。例えば、0x0aは改行を意味するし、0x0dが復帰を意味する。0x0c(Control-L)は、画面消去を意味することがある。また、端末によってはエスケープに続く文字は特別な意味として解釈する。

これらの特殊文字の他に、データ転送時のフロー制御に使われるコントロール文字もある。Control-Sが送られてきたら、データ送信を一時中断し、次にControl-Qが送られてきたら再開するのがXON/XOFF制御(X制御)である。このようなコントロール文字がテキスト中に含まれていたらどうなるだろうか。テキストを画面に表示している途中で、Control-Sが現れたら、その後に端末から何か送信しようとした時に、まだControl-Qを受け取っていないので、待ち状態に入ってしまうかもしれない。そうなると、お互いにデータを待つことになってしまい、相互の通信が破綻する。

パソコンや各種端末に関しては、ESCに続く文字によって文字や画面の表示属性、カーソル位置の変更、画面サイズの変更を行なうことができるものがある。画面表示モードの切り換えや、特殊なコマンドを実行する機能を持ったものもある。しかし、これらの仕様は、ある程度一貫されているようで、それでいて全機種が共通というものでもない。 ネットによってはESCを文中に含めることを禁止していることがある。ESCシーケンスを使ってテキストを作ると、文字に色を付けたり、画面上の任意の位置にカーソルを移動できるため、面白い効果が得られるのだが、それも特定の機種のみで通用するという前提の下でのみ有効なのである。 例えば特定のパソコンでのみ使うという前提があるネットならよいが、ある人がカラフルな文章を掲示したつもりなのに、他のパソコンを使っている人が同じテキストを見ると、その後の文字の色が画面背景色と同じ黒(白?)になってしまい、全く読めないという悲惨な結果になるかもしれない。

ところで、テキストならばESCを使わないというルールを決めればそれで解決することだが、プログラムをそのままBBSに掲示したらどうなるか? プログラムのコードには任意の文字が含まれる可能性があり、ESCやコントロール文字を使わないようにしましょう、というわけにはいかない。 また、多くのBBSには、テキストの掲示する時に1行の長さの制限があり、また、全体で何行までという制限もある。このような制限も問題が発生する原因となる。

もう一つの大きな問題は、データエラーへの対策である。 最近はMNPモデムのように、エラーフリーの通信も簡単に実現できるようになったが、BBSが始まった頃には、300bpsで、エラー訂正機能など何もないモデムが主流だった。テキストの場合、文意を伝えるというのが目標となるのだが、人間自身に強力なエラー修正機能が働くので、回線のノイズ等が原因である程度データが化けても、意味を理解するのに壊滅的なダメージを与えるということは、あまりない。むしろ、文章を書く人が文章技術が問題になって、意図が伝わらないことの方が圧倒的に多いようである。しかし、プログラム等のデータは、1バイトたりとも化けては役に立たなくなるのである。

化けるというのは、いろいろな場合が考えられる。文字通り、送信側が'A'を送ったのに、受信側が'C'を受け取ってしまった、というような場合がある。また、データを送ったのに、何らかの理由で受信側が受け取れない場合も考えられる。さらに、データを送っていないのに、回線のノイズが発生して、それを受信側がデータと誤認識して受け取ってしまう場合もある。

この他にも、バイナリデータの場合には、データの最後をどうやって判定するかという問題、ファイル名、ファイルの作成時刻をどのように伝えるか、という問題がある。

もう一つの問題について、今回のテーマからは逸れるが、簡単に触れておく。プログラムに限らないが、複数のファイルをまとめて扱いたい場合がある。例えばプログラムなら、そのマニュアルと、サンプルのデータや、プログラムソース、作者の紹介文などを、一まとめにして配布したい。また、プログラムが大規模になってきたり、データの構成の都合によっては、ディレクトリ構造をそのまま保った形で公開したい、という要求がでてくる。つまり、ファイルそのものを転送するだけでなく、複数のファイルの関係についても、情報として転送したいということだ。

これを実現するには、アーカイバというプログラムを使う。アーカイバを使って作成した、データを集めたデータのことを、アーカイブ、またはアーカイブファイルなどと呼ぶ。アーカイブというのは、日本語にすると書庫という感じになるが、プログラムやデータをまとめたものというイメージにはいま一つぴったり来ないのか、アーカイブと読んでしまうことが多いようだ。

最近、アーカイバはデータを圧縮するプログラムだという説明をよく見かけるようだが、これは誤りである。アーカイバは、複数のファイルをまとめて一つの(アーカイブ)ファイルの中に格納したり、逆に、一つのまとまった(アーカイブ)ファイルの中から、元の状態のファイルを取り出すプログラムである。圧縮とは全く無関係である。ただ、DOSで使われているアーカイバの中には、ファイルを格納する時に、データを圧縮する機能「も」持っているものが多い。データを圧縮してアーカイブのサイズを小さくすれば、いろいろな意味で得をするからである。これを勘違いして、アーカイバというのはファイルを圧縮してまとめるものだ、と誤解する人が多いのだと思う。

UNIXでは、tar形式というアーカイブの形式が、かなり広く使われていて、これは規格にもなっている。この形式を扱うアーカイバはtarと呼ばれており、UNIXシステムには標準として用意されている。また、DOSにもいくつか移植されているので、現在は多くの環境で使うことが可能である。また、UNIXではarというアーカイバもある。これらのアーカイバは、データ圧縮の機能はない。

いずれにしても、アーカイバを使うことにより、複数のファイルをまとめて一つのものとして扱うことが可能になるので、問題は、このデータをどうやってBBSに掲示するか、あるいはそれ以外の方法で解決することができるか、ということになる。

BBSにテキストを掲示するのと全く同じようにバイナリデータを掲示することができない理由は、コントロール文字などが特殊な扱いになるため、すべてのコードが掲示できるとは限らないからだった。この点に注目すれば、ただちに一つのアイデアを思い付く。 すなわち、掲示できるコードだけを使って、バイナリデータを表現することが出来ればよいのである。 バイナリデータをうまく変換して、コントロール文字が含まれないようにすれば、BBSにテキストを掲示するのと同じ手順でバイナリデータも掲示できる。 UNIXの世界では、uuencode、uudecodeというコマンドがある。 日本のネットでは、黎明期においてはHEXのコードに変換して掲示することもあったが、ISH形式という大ヒットした形式がメジャーとなり、今も主流として使われている。これはListのような感じのテキストになる。これをこのまま読んでも何だか訳がわからないはずだが、ishというプログラムを使えば、変換前の状態に戻すことができる。 ishが爆発的に広まったのは、多少の冗長性を持たせる代わりに簡単なエラー修正が可能であったことと、フリーソフトウェアとして配布されたことが理由であろう。

ish形式の欠点は、まさにこの冗長性であった。バイナリデータをテキストに置き換えるのだから、必然的にデータのサイズは増加する。その分、通信に必要な時間も増える。 アーカイバーを使った後にishを使うという二度手間も面倒になる。

そこで、バイナリデータを転送する間は、特別な手順を決めておき、通常は掲示できないようなデータも通すようにしよう、という発想が出てくる。これがファイル転送プロトコルとして現実化したのだ。

1.2 ファイル転送プロトコル

1.2.1 ファイル転送プロトコルの種類

最初に全世界に広まったファイル転送プロトコルはXMODEMである。XMODEMは時代の要望に従って改良された。XMODEMが主流の時代において、最も切実な問題はデータ化けである。電話回線の品質は専用回線に比べるとかなり悪い。ノイズによって文字化けすることが頻繁に発生する。XMODEMは最初1バイトのチェックサムでエラーの検出を行っていたが、これではパワーが足りないということで、CRCを使ってエラー検出するように改良されたものが生まれた。さらに、速度を改善するためにブロックの長さを1024バイトに拡張したものが生まれ、バッチ転送、スライディングウィンドウ、途中で中断したデータの続きを受け取る機能などが追加されたYMODEM、ZMODEMという系譜を生むことになる。

全く別の流儀として、特にUNIX上では、Kermitというプロトコルが使われることもあった。 商用ネットとしてはCompuServeがB Protocolを改良してQuick B、そしてB Plus Protocolを開発した。これはNIFTY-Serveでも現在使われているプロトコルである。ところが、このプロトコルは他の大手ネットは採用されなかった。 特に日本では、PC-VANにおけるQuick-VAN、アスキーネットにおけるTransItのように、独自の通信プロトコルを用意して、各社独自路線を走ることになってしまった。この結果、ユーザーは利用するネットに応じて別のプロトコルを用意しなければならなくなっており、この混迷した状況はあまり望ましいものとは言えないようである。

1.2.2 通信プロトコルの機能

通信プロトコルに要求される機能は、全てのコードを含むデータを問題なく転送できることである。 テキストファイルなら、画面上でエコーバックしたものを確認することができるという特徴もあるが、さらに大きな特徴としては、行という単位が割合明確であることが重要である。BBS等では、発言時に、ここで発言が終わるということをどうやって指示するかが問題になる。 通常、文章では現れることのないような文字列、"/e"や"."のみが含まれていることをもって発言終了とするものが多い。NIFTY-Serveのように"//"で終了になってしまうためにC++のソースプログラムを書いたら途中で終わってしまったという笑い話もあるが。 とりあえず、このような方法でテキストは最後を知らせることができる。 テキストが行ごとに改行コードによって区切られているのに比べ、一般的なデータはどのような区切りになるかわからないし、プログラムの実行形式のように、簡単に区切りを決めることのできないデータもある。通信プロトコルはこのようなデータもやりとりできるように設計しなければならない。 そこで、バイナリのデータを問題なく送るために、次のように処理する。 まず、データを単位ごとに分割する。 この単位のことは、プロトコルによって呼び名が異なるが、 ブロックとか、パケットと呼んでいる。今回はとりあえずパケットと呼ぶことにする。 パケットの内容は、データだけではなく、それに付随した内容、例えばパケットの番号やエラー検出のための情報を含んでいる。従って、データを生のままで送るよりは、実際に送受するデータの量が多少増えることになる。 このようなパケット以外に、コントロールのために特別なコードも用いる。データが終了した時に、これで転送完了というコントロールを送信するか、または、データが終了したことを通知するための特別なパケットを送信する。 これにより、データの終了を相手に確実に伝えるのである。

通信プロトコルに最も期待されることは、ファイルをエラーなしで確実に転送することである。 バイナリのデータはテキストファイルを画面上で確認しながら文字化けのあった箇所を修正するようなわけにはいかない。 エラーフリーは絶対必要な条件となる。 これを達成するためには、次の2つの機能が必要である。まず、エラーが発生した時に、それを検出して、何等かの方法で対策できること。これは、検出の手順がまず重要であり、さらに、エラーが発生した時に、どのようにして修正するかという点がポイントになる。 方法としては、ある程度冗長なデータを生成しておき、多少のエラーは受け取り側で修正するようなことも考えられるのであるが、現在主流の通信プロトコルにおいては、 パケット単位でエラーの有無を判断し、もしエラーがあれば再度同じパケットを送信するように送信側に指示することによって、エラーを回避しているものが多い。 もう一つの機能は、全ての文字をデータに含むことが可能にすることである。XMODEMのように、全キャラクタが通ることを、あらかじめ回線の前提条件としてもよいが、その場合にはコントロール文字の扱いに難があるので、一般的手法としてはコントロール文字をクオートすることによりこの問題を解決する。

1.2.3 用語説明

いくつか、通信プロトコルに特有な用語について説明を試みる。

◆ アクナリッジ、ネガティブ・アクナリッジ
パケット毎にデータを送る機能を実現するには、送信側、受信側の役割を次のように分担すればよい。まず、送信側はパケットを送り出す。受信側は、パケットを受け取る。これらは当然の処理である。 しかし、実際はデータが化けたり抜けたりして、正常に送受できないことがある。このような場合には、受信側から送信側に、データが受け取れなかったとか、正しく受け取れたとか、知らせてやることになる。このような応答のことを、アクノリッジという。

アクノリッジには2種類ある。データを正常に受け取ったという合図のためのアクノリッジのことを、ポジティブアクノリッジ(ACK)と呼ぶ。 これは要するにOKという意味である。 これに対して、データが正しく受け取れなかった、すなわち に異常があったことを知らせる合図のためのアクノリッジを、 ネガティブアクノリッジ(NAK)という。これは要するにNGという意味である。

送信側は、NAKが戻ってきた場合には、それに応じて適切な処理をしなければならない。おそらく、もう一度パケットを送信するか、処理を全て中断するかである。 このようにNAKの判断は重要であるが、ACKが戻ってきた場合は、基本的に次々とデータを送っていればよい。 そこで、通信プロトコルをうまく設計することによって、ACKを受け取る処理を省略することができれば、ACKを待つための時間が節約できるので、データ転送を高速化することが可能である。 便りのないのは良い知らせと解釈するのである。

ACKやNAKに用いられるキャラクタ、あるいはデータは、コントロールコードのACK、NAKだけではなく、プロトコルによって異なっている。

◆ エラー検出
バイナリのデータを転送するためには、全てのデータを誤りなくやりとりできなければならない。では、全データが正しく受信できたことを、どのようにして確認すればよいだろうか。ファイル転送プロトコルでよく使われるエラー検出方法は、チェックサムとCRCである。 チェックサムは、ブロック毎に、全てのバイトの情報を加算した結果を比較する方法である。処理は簡単だが、合計が同じになるような化け方でデータが変化していると検出できないという欠点がある。また、チェックサムの実現方法としては、単に足し算するのではなく、計算結果の下位の8ビットだけを比較するようなものがあり、この場合はさらに誤りを見落とす確率が高くなる。 CRCは、よりチェック率を向上させる方法である。原理は今回は説明を省略するが、実用上は、エラーが発生した時の検出率がチェックサムよりも高いことだけ知っていればよい。

◆ クオート
コントロール文字をそのまま転送すると不都合が発生する場合が考えられる。例えば、XON/XOFF制御に用いられるControl-S、Control-Qがデータの中に含まれているかもしれない。このような文字をXON/XOFF制御ありの状態の回線で送信すると、データが相手方にそのまま伝わらないだけでなく、フロー制御の信号が来たと錯覚してしまい、データが途中で止まったままになる危険もある。XMODEMでファイル転送しようとした場合に、まさにこの問題で転送失敗するケースがよく見られる。

この問題を回避するには、コントロール文字がデータに含まれていた場合に、コントロール文字以外の文字に置き換える手順を決めておく。データを送信する側は、コントロール文字が現れた時点で、この手順に従い、通常の文字に置き換える。データを受信する側は、置き換えられた文字を、元のコントロール文字に戻す。これで、コントロール文字を含んだデータも問題なく転送することができる。このような処理をクオートと呼んでいる。

例えば、B+プロトコルの場合には、コントロール文字が現れたら、0x10に続いて該当コントロール文字に0x40を加えた値に相当する文字を置くことによって、コントロール文字を回避している。例えば、Control-Sは、0x10 'S' という2バイトに置き換えられる。こうすれば、データ中にはControl-Sそのものは現れないので、XON/XOFF制御と衝突することによる不都合はない。ただし、本当に回線側の都合でXON/XOFF制御が行われた場合には、プロトコルの処理以前の段階でそれを処理しておかなければならない。

◆ スライディング・ウインドウ
現在、実際にネットにアクセスして、XMODEMとB+のデータ転送速度を比較すると、2倍程度の差がある。なぜこれほどの差が生じるのかというと、パケット回線処理とデータ転送プロトコルのパケット処理とが衝突した時に発生する遅延の効果が最も影響していると考えられる。

XMODEMは、データを1ブロック送ると、それが正しく受信されたかどうかの確認応答を待ち、OKであるという返事が来てから次のブロックを送る。この方法だと、どのような問題が想定されるか。パケット回線というのは、ある程度まとまったデータを一度に送信する仕組みになっている。例えば、128バイトのデータを受け取った時点でそれを一度に送信することになる。 パケットを送信するタイミングとしては、これ以外にも特定のコード(例えば改行コード)を受け取った時に送信するという設定もある。 データが連続してよどみなく送信されていれば、特に問題はないのだが、128バイト未満のデータを送る場合には、128バイト受け取るまで待つだけでは、いつまでたってもデータが送られない。そこで、あらかじめタイムアウト間隔を決めておいて、ある時間待っても次のデータが来なければ、今までに受け取っているデータを送信してしまうのである。 タイムアウト間隔は、インタラクティブにコマンドを送信するような場合には問題にならない程度の間隔に設定されるのであるが、データを送受信するような場合にはこれが問題になるのである。例えば、XMODEMだと128バイトのデータを送る時に、まず送信側がプラス数バイトのデータを付加するので、最初の128バイトはただちに送られるが、余った数バイトが送られるまでに、タイムアウトになるまでの時間が経過する。 これで受信側がデータを受け取ったことになるが、さらにデータが正常に受信できたことを返信する時に、1バイトのACKを返信しなければならない。これがまたタイムアウトになるまで待つことになる。例えばタイムアウト間隔が0.1秒に設定されていたとすると、合計0.2秒が128バイトのデータ転送毎に余計に必要となる。これは2400bpsで転送する場合には48バイトのデータを送ることのできる時間に相当する。

この問題を解決するには、まず一度に送るデータの量を多くすることが考えられる。一度に大量のデータを送ることにより、確認のデータを送る回数も少なくなるし、途中の回線のパケットサイズに比べて長いデータであれば、待つ回数も少なくなる。ただし、回線の状態によっては、あまりパケットの長さを大きくしては、逆効果になることも考えられる。パケットが長くなればなるほど、その中でデータエラーが発生する確率も高くなるし、エラーが発生した時にリトライとして送信しなければならないデータ量も多くなるからである。

そこで考えだされたのは、ACKを待たずに次のデータを送ってしまうという方法である。最初のパケットを送ると、ただちに次のパケットを送信する。受信側は、最初のパケットを受信してからACKを送ることになるが、回線の遅延などの影響で、この時には既に送信側は次のパケットの送出を始めている。ここで問題は、データにエラーが発生した場合である。送信側は既に次のパケットを送信し始めているからだ。 通信プロトコルは、パケット毎に番号を付けるようになっているので、受信側が、どのパケットに対してエラーが発生したのかを返信するようなメカニズムにしておけば、エラーが発生したパケットだけを再度送信するような処理ができればよい。 送信側は、このような場合を想定して、ある程度以前に送ったパケットもデータを保持しておく。このような手法をスライディングウィンドウと呼んでいる。これにより、送信側はよどみなくデータをどんどん送ることが可能になるから、待ち時間は殆ど無視できることになる。

◆ 行末処理
テキスト形式のデータを転送する場合には、行末の処理を行ってくれるプロトコルもある。テキストの行末は、CR、LF、あるいはその組み合わせで表現されるのだが、問題はその組み合わせである。CP/MやMSDOSで使われているのはCR+LFの組み合わせであり、現在多くのネットでこの組み合わせが指定できるようになっている。これ以外には、UNIXのようにLFだけで行末を意味するシステムもある。またはCRのみで改行を意味するシステムもある。例えばUNIXで作成したテキストファイルをDOSにそのまま持ってくると、CRがないために行ごとに行の先頭に戻らない、変な表示になってしまうことがある。

◆ レジューム
レジューム機能というとブックパソコンの電源を切った時の状態を保存しておき、次回電源を入れた時にそこから再開できるような機能をイメージするかもしれないが、レジュームというのはもともと復元するという意味であり、通信プロトコルではこの機能はファイルの途中からの送信が可能であることを意味する。 あまりあって欲しくはないことだが、大量のデータを受信中にトラブルでハングアップしてしまったり、センターがダウンしたり、キャッチホンに他から電話がかかってきたり、ということは経験した人も多いだろう。このような場合に再度初めからデータを受け取るのは大変だが、中断した所から続行できれば便利である。特に、電話回線を使ったファイル転送は、大量のデータ処理にはかなりの時間がかかるので、このような処理はBBSを利用する場合に特に便利であると言えよう。

基本的に、この機能そのものを実装は簡単である。受信側が指定したバイト位置から、送信を開始すればよいだけだ。もちろん、受信側は、指定したファイルに受け取ったデータを追加しなければならない。従って、問題は、どのようにして受信側がその情報を送信側に送るかということである。

プロトコルによっては、誤って違うファイルを途中から受け取ったりしないようにする処理が追加されている。最も確実なのは、既に受け取ったデータを全部比較することであるが、これでは最初からデータを全部送り直すのと同じ時間がかかってしまうのでお話にならない。そこで、よく使われている手法は、ファイルの途中までのCRCを計算し、比較するというものである。CRCが一致しない場合には、異なるファイルと判断し、データを最初から送り直すことにする。

◆ コントロールコード
0x00〜0x1fに相当するコードで、プロトコルによって、実際に利用するコントロールコードはこの中の一部である。表1を参照。
表1 コントロールコード一覧

表記意味
Control-@NUL(0x00)Null, Idle
Control-ASOH(0x01)Start of heading
Control-BSTX(0x02)Start of text
Control-CETX(0x03)End of text
Control-DEOT(0x04)End of transmission
Control-EENQ(0x05)Enquiry
Control-FACK(0x06)Acknowledge
Control-GBEL(0x07)Bell, beep, or fleep
Control-HBS(0x08)Backspace
Control-IHT(0x09)Horizontal tab
Control-JLF(0x0a)Line feed
Control-KVT(0x0b)Vertical tab
Control-LFF(0x0c)Form feed (top of page)
Control-MCR(0x0d)Carriage return
Control-NSO(0x0e)Shift out
Control-OSI(0x0f)Shift in
Control-PDLE(0x10)Data link escape
Control-QDC1(0x11)Device control 1, XON
Control-RDC2(0x12)Device control 2
Control-SDC3(0x13)Device control 3, XOFF
Control-TDC4(0x14)Device control 4
Control-UNAK(0x15)Negative acknowledge
Control-VSYN(0x16)Synchronous idle
Control-WETB(0x17)End of transmission block
Control-XCAN(0x18)Cancel
Control-YEM(0x19)End of medium
Control-ZSUB(0x1a)Substitute
Control-[ESC(0x1b)Escape, prefix, altmode
Control-\FS(0x1c)File separator
Control-]GS(0x1d)Group separator
Control-^RS(0x1e)Record separator
Control-_US(0x1f)Unit separator

(フィンローダ NIFTY SERVE FPROG SYSOP)

(C) 1992,1998 Phinloda, All rights reserved
無断でこのページへのリンクを貼ることを承諾します。問い合わせは不要です。
内容は予告なく変更することがあります。

[Home]