題名:ネットワークについて

五郎の入り口に戻る

日付:2000/7/1

 この文章について | ネットワークの動作概要 | Physical Layer:物理層 | Media Access Control SubLayer | Logical Link Sublayer | Network Layer | Transport Layer


Transport Layer

さて、いよいよ本文章でカバーする範囲の最上位層(実際には更に上位の層があるが)Trasport Layerである。

 

すぐ下のNetwork Layerは数々の異なるネットワークを経由して「目的地」までパケットを運んでくれるものだった。この場合の「目的地」とは「目的のマシン」を意味している。

 

さてTransport Layerの機能は以下のように定義される。

「異なる(または同一の)マシン上で実行されるプロセス間のEnd-to-Endの通信を行なうもの」

 

ここで、「マシン」よりも更に目的地を細分化して「プロセス」という言葉を目的地にした。実際のところ行ないたいのは「マシンとマシンの間の通信」ではなく、「マシン上で実行されるプログラムと別のプログラムの通信」なのであるから、本当に「相手先」を指定しようと思えば「プロセス」の指定までを行なう必要がある。

 

さて、End-to-Endの通信というと、一つ飛ばして前の「Data Link layer」を思い出す。Data link Layerがやることは、「同じ媒体を共用している2点間での通信」だった。Transport Layerが目的とする2プロセスの間にはあれやこれやの異なったタイプのネットワークが横たわっているだろうが、それはNetwork Layerが面倒を見てくれることになっている。となればここで気にするのは確かに「2点間の通信制御」にかかわる事柄だ。

 

実際Transport layerで使われる技術にはコンセプト的にData Link Layerと同じものが多い。しかしながら厳然として違いも存在している。

 

・ユーザー指向:Transport layerの一つ上は、多くの場合アプリケーションプログラムである。つまりアプリケーションを書く人間にとってみればTransport layerこそが「ネットワーク」であるからして、それを考慮した機能を持たなくてはならない。つまり、下に存在しているわけのわからないネットワークの状況などはうまく覆い隠して、ユーザーにとって直感的に分かりやすいものである必要がある。

 

・通信の品質とサービスの調整(交渉):スループット、伝送遅れ、信頼性などについて、通信を行なうプロセス間で通信開始時に交渉を行なう必要があるかもしれない。

 

・品質の高い通信最初の「ネットワーク概要」のところで書いたように、Networklayerは常にちゃんとしたパケットの送受信を保証してくれるわけではない。(広く使われているIPとなると、最初からそうしたエラーなしの通信を行なうことさえ考えていない)となれば、上にのるアプリケーションに負担をかけまいと思えば、このTransportLayerでちゃんとした品質の高い通信を行なう工夫をする必要がある。

 

・Addressing:「ユーザー指向」については前述した。人間とコンピュータの間には深くて長い溝があり、コンピュータにとってわかりやすいものは、人間にとって分かりづらく、Vice Versaである。となれば、人間にとってわかりやすい標記から、パケットに埋め込むことのできるようなAddressに変換する仕組みを考えてやる必要がある。

 

・サブネットでのバッファ:Data linke Layerの場合、間にあるのは物言わぬ媒体だったから問題なかったことが、ここでは問題になりかねない。下にあるのはNetwork Laeyrその他大勢なのだ。network LayerのところでCongestion Controlするためにはバッファが必要、というのは前述した。となると送られたパケットは途中のネットワークにおいて、やたらと長い時間バッファにほうり込まれてしまうかもしれない。そして古くなってしまったパケットがとんでもないタイミングで届く事だってありえる。

 

・動的なフローコントロール:Data link layerのところで述べた「バッファを前もって割り当てておく」という方法はTransport Layerでは使えない。なぜなら一本しかない媒体を数百ものプログラム-プロセスが共用しているかもしれないからだ。

 

また相手側にデータを受け取るだけのバッファなりなんなりがない限りにおいてデータを送っては行けない。Data link layerの送受信方法として、「受信側にバッファがなくて、データが受け取れなかったらたんにAckを返さない」というのがあった。同じ方法をTransport Layerでとってしまうと、途中経由するNetworkのリソースをやたらと無駄遣いすることになってしまう。したがって受信側にバッファがない場合には、なんらかの方法でそれを知らせ、送信を止める必要がある。

 

 

・Congestion Control:Internetで使われているconnectionlessサービスでは、Transport LayerがCongestionControlを行なう必要がある。

 

・Connectionの確立、終了;Conenction Orientedサービスの場合は、Connection 確立時に最初に書いた「あれこれ調整した項目」について調整する必要がある。そして通信終了時には、両方のプロセスが「送りたいものは全部送った」ということを確認する必要がある。なんでこんなあたりまえのことを書くか、といえば、後者の「Connectionの終了」は言うほど簡単ではないからだ。これについては後述する。

 

さて、ここまでのlayerでは基本的にEE384の講義ノートにしたがって説明を行なってきた。この講義はOSIを強く意識したものになっているが、当時と今とでは状況が違う。今やOSIのスタンダードなど使えっているのは某N○○データがお役所向けに作ってるシステムくらいであり、その他のほとんど全ての分野ではTCPもしくはUDPがのしててきている。

 

したがってこのlayerの説明は、本講義と同じ教科書をベースにしているhttp://www.cs.wpi.edu/~cs513/f99cew/の内容をベースにし、TCP及びUDPの説明を中心に行なう。

 

まずは比較的単純なUDPのほうから。。

 

User Datagram Protocol(UDP)

UDPは「信頼性のない」Datagramのサービスを提供する。「信頼性がない」とは早い話し、IPのDatagramサービスをそのまま使い、やれAckだやれ再送信だなどはいっさいおこなわない、ということだ。

 

それでは何もしていないではないか、と言われるかもしれないが、ちゃんと階層を一つ追加しているだけのことはしている。つまり冒頭で述べた「マシンではなく、プロセスに対する通信」を実現するため、プロセスを指定する機能を持っている。問題はどのように指定するかだ。

 

例えばたいていのOSでは、個々のプロセスというのは固有の識別子を持っている。(そうでなくては区別がつかないではないか)その識別子を使ったらどうだろう?

 

そうすると確かに識別は可能となる。ただしいくつか問題がある。もう前提を書いているところで露呈している気もするが、まずOS毎にプロセスのID番号付与の仕方は異なる。となると相手が何者かわからない状況ではとても使いづらいことになる。またサーバーが一旦ダウンしてまた復活したとしよう。OSによっては(というか大多数の場合はそうかもしれないが)前と同じ識別子が付与されるとは限らない。となるとダウンしなかったほうは「なんやねん」」ということになる。

 

こうした問題を解決するために、TCP及びUDPではポートというものを用いている。(Transport層になるとユーザー指向だけあって、ポート番号という言葉は目にしたことがあるかもしれない)具体的には番号だ。この番号をあらかじめ双方で決めておけば、「なんとかマシン上の何番ポート」と指定して通信が行なえるわけである。

 

さて、ここで出てくるポート番号は16ビットであるが、0−255の番号は「有名なサービス」に向けて予約されている。ユーザーは残りの番号を自由に指定していいことになっているが、もちろん(意図的にやる場合は別として)重複があってはならない。

 

これがわれわれのようなエンドユーザーであっても「ポート番号」という呪文を目にせざるを得ない理由の一つでもある。例えばかわいいペットがメールを運んでくれるソフトウェア、Postpetであっても「難しい設定」なる項目を選ぶと

「SMTPポート番号、POPポート番号」

なる呪文を目にしなければならない。

「*通常変更する必要はありません」

と書いてあるが、場合によってはなんらかの理由により、SMTPであるとかPOPとかいう呪文が意味するサービスが別のポート番号を使用していることもあるかもしれない。となれば、ここを変更する必要がでてくるわけだ。

 

さて、UDPのパケットはヘッダーとデータからなっている。ヘッダーに含まれるのは以下のデータだ。

Source Port(16ビット):送り主のポート番号

Destination port(16ビット):送り先のポート番号

length(16ビット):データグラムの長さ

Check Sum(16ビット):読んで文字のごとく。ただしこれはオプションである。

 

かくのとおり、UDPヘッダーには、送信側と受信側のポート番号しかはいっていない。このデータはそっくりそのままIPパケットのデータ部分におさまるので、全体としてはマシンを指定するIPアドレス+ポート番号の情報が記載されていることになる。

 

人によっては、この「UDPはアドレスの一部しか持っていない。残りは下位レイヤーの情報でおぎなう」という方法は、今迄になかったものだと感ずくかもしれない。例えばネットワークレイヤーであるところのIPプロトコルはそれ自体でちゃんと相手のマシンを指定するアドレスを持っている。前述した参考ページには

「これはレイヤー分けの原則には反しているが、現実のとの間の妥協で生まれた結論である」

と書かれている。

 

さて、かくのとおりUDPはほとんどIP+ポート番号であり、エラー処理やCongestion Controlのための情報は何一つ持っていない。つまりエラー処理がおころうが渋滞が起ころうがしらんぷりだ。ではなぜこんなプロトコルが存在しているかといえば、処理が簡単で、スピードが速いからである。ある天下の電機メーカーがお役所に納めているシステムで、ときどき通信データが化ける、という問題があった。設計書にはTCPで接続されている、と書いてある。おかしいTCPであれば、仮に通信回線でビットがひっくりかえったとしても、ちゃんとエラーチェックを行なっているはずなのだが、、と疑問に思っていたが、某電機メーカーの人間はいとも明快にその理由を説明してくれた。

 

「TCPでエラーチェックをちゃんとやると、ハードの処理能力がおいつかなくなりますので、エラーチェックをはずしています」

 

エラーチェックを行なわなければ大事なデータが化けるのは当たり前である。こういう「常識」が名だたる電機メーカーと日本一のシステムインテグレーターの中でまかり通っている、というのは外部から見れば信じられないことだろうが事実である。こうした「使い方」は私から見れば狂気の沙汰としか思えないが、ちゃんとしたUDPの使い道もある。例えばリアルタイム性が何よりも要求され、多少データーが間違っていても問題がない音声データの伝送などの場合だ。

 

次の章


注釈