アカデミック

【初学者向け】マルチメディア通信<TCP/IP編>

この記事では,マルチメディア通信に関わる知識を簡単にまとめていきたいと思います。ただし,全ての知識が詳しく網羅されている訳ではありません。また,分かりやすいように多少意訳した部分もあります。ですので,参考程度におさめていただければ幸いです。

間違えている箇所がございましたらご指摘ください。随時更新予定です。他のマルチメディア通信に関する記事はコチラのページをご覧ください。

TCP/IPとは

以下の記事で簡単に説明しています。

【超初心者向け】プロトコルとは?意味と使われ方をTCP/IPを用いて分かりやすく解説します!本記事は教養記事シリーズその23です。その他の教養記事はコチラの目次をご覧ください。 プロトコルとは プロトコル(p...

TCPで大切な概念

TCPでは,信頼性のある「再送制御」,通信相手に合わせた「フロー制御」,ネットワークの混雑状況に合わせた「輻輳制御」がキーワードです。また,送受信者間で同じプロトコルに従っているという「公平性」も重要になってきます。

4つの伝送方式

IPプロトコルでは,パケット通信が行われます。パケットとは,データを小分けにした小包のことです。ちなみに,パケットにはヘッダ(荷札)とペイロード(荷物)が含まれます。パケットの伝送には,4つの方式があります。

●バルクデータ伝送
●対話型伝送
●イベント駆動型伝送
●実時間データ伝送

以下では,クライアントとサーバ間でデータを伝送することを考えます。バルクデータ伝送は最もベーシックな方式で,クライアントからサーバに向けて要求・確認応答(ACK)を送り,サーバはそれに対応する形でパケットを連続的に送り続けます。対話型データ伝送では,クライアントのACKを細かく区切り,それぞれのACKに応答を行うことで処理が進んでいきます。イベント駆動型データ伝送は,クライアントからのACKがマウスやキーボード入力などのイベントの発生に基づく方法です。実時間データ伝送は,カメラやマイクで収集されたデータをパケットとして一定の帯域幅で送る方式です。

これらの伝送方式を「遅延時間」「信頼性」に基づいてみていきます。

【遅延時間の要求】
●バルクデータ伝送
→データの最後が出来るだけ短時間で届くこと
●対話型データ伝送
→相手からの応答時間が短いこと
●イベント駆動型データ伝送
→クライアントからサーバへのメセージが短時間で届くこと
●実時間データ伝送
→遅延時間/遅延時間の揺らぎの値が小さいこと

【信頼性】
●実時間データ伝送以外
→パケットが喪失した場合には再送orエラー訂正
●実時間データ伝送
→パケットが喪失しても出力することができる

TCPとUDP

こちらのサイト[外部リンク:gihyo.jp]では,以下のように両者をまとめています。

●TCP
ー信頼性が高い
ーコネクション型(双方向的)
ーウィンドウ制御/再送制御/輻輳制御/を行う
「荷造り付き宅配サービス」のよう

●UDP
ー信頼性が低い
ーコネクションレス型(一方向的)
ー処理が簡単で遅延が少ない
「ただの宅配サービス」のよう

他にも,例えばTCPでは一対一通信,UDPでは一対多通信も可能であることが挙げられます。

まず,TCPとUDPはトランスポート層のプロトコルという点で共通しています。トランスポート層ではデータの送受信が行われることから,データの受け渡しに関する信頼性を定めたプロトコルとも捉えられます。

TCPでは,データをパケットに分割する際に,しっかりと元に復元できるようなプロトコルを定めています。パケットの順番が途中で変わってしまったり,途中で損失した場合には,適切な処理を施せるようにデータを保持しています。

つまり,TCPはデータの送受信に関して信頼性を高めるような働きをします。メールの送受信やファイルの転送などで用いられるプロトコルです。

一方,UDPでは信頼性はそこそこにして,データのリアルタイム性を重視します。これは,TCPでは信頼性に重きを置きすぎていて音声や画像データの送受信に向かないという問題点があったことが発端でした。UDPでは,TCPでも行われているチェックサムの検出とエンドポイント(IPアドレス+ポート番号)の識別のみを行うのみです。UDPはデータ送信に関する制御をアプリケーションに任せるプロトコルともいえます。

データの送受信

データを送受信するためには,まずコネクションを確立する必要があります。TCPでは,「3-way handshake」によってコネクションを確立しています。「3-way handshake」では,クライアント側とサーバ側で3回のやり取りを経ることでコネクションを確立します。

3回のやり取りでは「SYN(Synchronize)」と「ACK(Acknowledgement)」が送られます。SYNはデータ転送の許可を尋ね,ACKは許可を与えます。

コネクションが確立した後は,データをパケットに小分けにして送受信します。以下では送信側のホストをS,受信側のホストをRとします。最も単純なアルゴリズムとしては,「SはRから応答を受け取ったらパケットを送る」「一定時間待って応答がなければ再送する」というものです。

しかし,このアルゴリズムではデータの送信速度がS/R間におけるパケットの往復時間(RTT:Round Trip Time)に律速されてしまうという限界があります。そこで,パケットにインデックス番号(Sequence Number)を振って,一度にパケットをまとめて送り応答では正しく受信できたデータの番号を添えるというアルゴリズムが考えられました。

送信側で溜め込むことができるデータサイズを「最大セグメント長」,受信側では「ウィンドウ」などと呼ばれることがあります。まとめて「バッファ」と呼ぶこともあります。

以下では,このアルゴリズムに関して「送信側」と「受信側」で工夫されている点についてみていきたいと思います。特に,データの送受信量を調整する「フロー制御」に焦点を当てていきたいと思います。

送信側

送信側で起こりうる問題としては,「The small-packet problem」が挙げられます。これは,送信したいデータサイズに対してヘッダー部分の占める割合が大きくなってしまう現象のことを指しています。例えば,Wikipedia[外部リンク:Nagle’s algorithm]の例のように,1byteのデータを送信したいときに,IPヘッダで20byte,TCPヘッダで20byteが付け加えられるため,合計で41byteのパケットを送信することになります。これでは,あまりにも非効率過ぎます。

この問題を解決するのが,Nagleアルゴリズムです。Nagleアルゴリズムでは,バッファ中に送達が確認されていないデータがある場合,以下の3つの条件のいずれかが満たされるまで,セグメントの転送を遅延させるというアルゴリズムです。

●最大セグメント長分のデータが送信できる状態になる
●バッファ中の全てのデータの伝達(ACK)が確認される
●遅延を開始してから一定時間(200msなど)が経過する

Nagleアルゴリズムは「低速域でまとめてデータを送信/高速域では遅延を小さくする」ことが目的になります。特に,低速回線における遠隔ログインサービスなどの性能を向上させることが期待できます。(マウス操作などの実時間性が求められるデータ送受信には向きません)まとめると,こんな感じです。

とりあえず基本的には最大セグメント長までデータを溜め込んでから送信するよ。そのときに,送信が完了していないものはずっとバッファで持ち続けるよ。でも,これだけだと遅延し過ぎてしまう可能性があるから200msが経過したらデータを送信するよ。

受信側

データをまとめて送るということは,受信側Rではデータを溜め込んでおく機構が必要になります。そこで出てくる概念が「ウィンドウ」です。ウィンドウとは,受信側で溜め込むことのできるデータサイズのことを指します。このウィンドウは,TCPのウィンドウ制御という働きによって動的に変更されます。

パケットをウィンドウがいっぱいになるまで送り続ける操作を「スライディングウィンドウ」と呼びます。

このウィンドウに関連して出てくる概念が「遅延確認応答」です。要するに,受信側からのACKを少し送らせて,ウィンドウサイズギリギリになるまでまとめてデータを受信し,まとめて処理しましょうという考えです。遅延確認応答により,転送セグメント数が減少してデータ伝送速度が速くなる一方で,バルクデータ伝送のような一方的な伝送方式には効果がありません。

もし受信側が遅延確認応答をしないと考えてみましょう。受信側が小さなパケットを受信するごとにACKを送ってしまうと,ウィンドウに空きがほとんどないのにACKを送っていることになります。この場合,TCPではそれに従うウィンドウ制御(本来もっと空きが出るはずなのに,空いているウィンドウが少ないと勘違いしてしまう)が働いてしまうため,非効率的なデータ伝送になってしまいます。これを「Silly Window Syndrome」と呼びます。

実装上は「遅延は最大500ms」「2セグメントを受信するごとにACKを送信」するようなアルゴリズムを採用することでうまくいくことが多いとのことです。ほどんどの実装では遅延として「200ms」を採用しているとのことです。

データに合わせて遅延確認応答を便乗させることを「Piggy Back」と呼びます。

「Silly Window Syndrome」を解消する具体的なアルゴリズムとしては,送信側/受信側共に,以下のいずれかが満たされた場合にデータを送信するというものが挙げられます。

【送信側】
●最大セグメント長のデータが送信可能
●告知されたウィンドウの50%が送信可能
●確認応答待ちのデータがない
(要するに,ある程度のデータが送信可能であれば送るよということ。)

【送信側】
●受信バッファが最大セグメント長分空いている
●受信バッファの50%が空いている
(要するに,受信バッファの空きが少ないときにはACKしませんよということ。)

Nagleアルゴリズムと遅延確認応答の衝突

これらの送信側と受信側の工夫は,相容れない場面があります。送信側のNagleアルゴリズムにおける「ACKが確認されていないデータは持ち続ける」というルールと,受信側の遅延確認応答における「ACKはなるべく送らないようにする」という性質が衝突してしまうのです。最悪の場合には,両者のデータ送信の基準が「一定時間経過したら」という条件になってしまうため,非常に効率の悪いデータ伝送になってしまうのです。

輻輳制御

輻輳とは,データ(など)が一箇所に集中してしまう現象のことを指します。輻輳を避けるため,そして輻輳が起きてしまった時のために,TCPでは輻輳制御が行われます。輻輳制御では,一度に送ることのできるデータサイズ(輻輳ウィンドウ)を制御することで,輻輳を防ぎ,輻輳に対処します。

TCPでは,受信側から送り返されるACKだけを頼りにして輻輳を検知します。例えば,一定時間内にACKが確認できなかった場合,同じACKが続けて確認された場合などが輻輳とされます。

以下では,こちらの記事[外部リンク:第1回 TCPの輻輳制御とは何か]を参考に,主要な3つの要素「スロースタート」「輻輳回避」「高速リカバリ」についてまとめておきます。

スロースタート

送信側の輻輳ウィンドウを1セグメントから2,4,8…と受信側から通知されたウィンドウサイズに達するまで指数関数的に増やしていく方法です。

輻輳回避

スロースタートにより輻輳ウィンドウを指数関数的に増やしていくと,輻輳が生じる場合があります。そのときに,輻輳ウィンドウを再度1に戻すのですが,そこからまた指数関数的に増やしてしまってはまたすぐに輻輳が起こってしまいます。そこで,線形的に輻輳ウィンドウを増やそうというのが輻輳回避のアイディアです。以下の式にしたがって「cwnd(輻輳ウィンドウサイズ)」を「mss(最大セグメントサイズ)」との比率によって定めます。

\begin{align}
\rm{cwnd} &= \rm{cwnd} + \frac{\rm{mss}}{\rm{cwnd}}
\end{align}

高速リカバリ

先ほどは,輻輳を検知したときに輻輳ウィンドウを1に戻しましたが,これは少し効率が悪い場合があります。そこで,同じACKが続けて3回送られてきたときに,そのセグメントを再送する高速再送というしくみと共に,輻輳ウィンドウを下げ過ぎないようにしようというアイディアが高速リカバリです。具体的には,輻輳が検知された際には輻輳ウィンドウサイズとして,輻輳検知時の半分に3を加えたものを採用します。

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です