BitTorrent プロトコル仕様書

BitTorrent プロトコル仕様書

以下の内容は Bram Cohen さんによる BitTorrent protocol specification の日本語訳です。翻訳者の英語読解力不足のため、訳文には若干怪しい点があります。このプロトコルに沿ってダウンローダなどを実装しようという人は、必ず原文にも当たり内容を確認するようお願いします。


BitTorrent はファイル配信のためのプロトコルです。Web とシームレスに結合するため、ダウンロードするファイルを URL で指定できるよう設計されています。ひとつのファイルに対して多数のダウンロード要求が同時に発生した場合、ダウンローダ・プログラムはお互いにアップロードし合うことで帯域の消費を抑えながら多数の同時ダウンロードを可能にします。BitTorrent はこの点で通常の HTTP を使ったファイル転送に優っています。

BitTorrent によるファイル配信の構成要素は以下の通り。

  • 普通の Web サーバ
  • 静的な「メタインフォ」ファイル
  • BitTorrent トラッカ
  • 「オリジン」ダウンローダ
  • エンドユーザが使用する Web ブラウザ
  • エンドユーザが使用するダウンローダ

多数のユーザがひとつのファイルを一斉にダウンロードしようとしていると仮定します。

BitTorrent 使ってファイル配信をおこなうには、次の手順でホストを設定します。

  1. トラッカを起動(あるいは既に起動済みのトラッカを使用)。
  2. Apache または手元にある別の Web サーバを起動(あるいは既に起動済みの Web サーバを使用)。
  3. (まだ MIME タイプの設定をしていなければ) Web サーバの設定を変更して拡張子 .torrent を MIME タイプ application/x-bittorrent に関連付ける。
  4. 配信するファイルとトラッカの URL を使ってメタインフォ(.torrent)ファイルを作成。
  5. メタインフォ・ファイルを Web サーバ上に配置。
  6. メタインフォ・ファイル(.torrent)へのリンクを張った Web ページを用意。
  7. 配信するファイルを保持しているダウンローダを起動(このダウンローダがオリジンとなる)。

ユーザ側のダウンロード手順は以下の通り。

  1. (まだインストールしていなければ) BitTorrent インストーラを実行。
  2. Web ページへアクセス。
  3. .torrent ファイルへのリンクをクリック。
  4. ファイルの保存場所を指定してダウンロード開始、または中断していたダウンロードを再開。
  5. ダウンロードが完了するまでじっと待つ。
  6. ダウンローダを終了(終了しない限りダウンロードが完了してもアップロードは続行されます)。

ここでおこなわれる接続の内容は以下の通り。

  • Web サーバは通常と同じスタティックなファイルの配信を開始するとともにクライアント側の BitTorrent ヘルパーアプリケーションをキック。
  • トラッカはすべてのダウンローダから情報を受信し、その情報を元に生成したランダムなピアの一覧を返す。この通信は http または https を通じておこなわれる。
  • ダウンローダはトラッカに対し処理の進行状況を定期的に通知。またそれぞれのダウンローダはお互い直接接続し合ってアップロードとダウンロードをおこなう。これらの通信は TCP 上の BitTorrent ピア・プロトコルを通じておこなわれる。
  • オリジン・ダウンローダは完全なファイルを持っているため、アップロードだけをおこないダウンロードを実行することはない。ネットワーク上で完全なファイルを配信するためにオリジンは必須。ただしいくつかのダウンローダがダウンロードを完了しそのまま動き続けている場合は、しばらくの間オリジンを停止させることも可能。

メタインフォ・ファイルおよびトラッカのレスポンスは共に、シンプルかつ効率的で拡張性に富んだ bencoding (bee encoding と発音)という形式を用いています。bencoding メッセージは入れ子状の(Python の)辞書とリストであり、文字列と整数値を保持しています。辞書のキーにない値がセットされた場合もそれを無視するようになっているため、後から新たな内容を加えて拡張することも可能です。

Bencoding の記法は以下の通り。

  • 文字列はその長さを10進数で表した値で始まり、コロンで区切った後に文字列そのものを記述する。たとえば spam は 4:spam となる。
  • 整数は i の後にその値を10進数で記述、さらにその後に e を付ける。たとえば 3 は i3e、-3 は i-3e と表記する。値の大きさに制限はない。なお 0 で始まる数値 i-0ei03e のような表記は認められない。0 を表す i0e だけが有効。
  • リストは l の後に(エンコード済みの)要素を記述し最後に e を付ける。 たとえば ['spam', 'eggs'] は l4:spam4:eggse と表記する。
  • 辞書は d の後にキーとその値を交互に記述、最後に e を付ける。たとえば {'cow': 'moo', 'spam': 'eggs'} は d3:cow3:moo4:spam4:eggse、{'spam': ['a', 'b']} は d4:spaml1:a1:bee と表記する。なお辞書のキーは必ず文字列であり、ソートされた順に記述されていなければならない(ソートの順序は辞書順や数値順ではなく文字コード順)。

メタインフォ・ファイルは次のキーを持つ bencoding 済みの辞書です。

announce

トラッカの URL。

info

以下のキーを持つ辞書を指します。

name の値はファイル(またはディレクトリ)として保存する際の名前となる文字列です。これには補助的な意味をしかありません。

piece length の値はファイルを分割する際のサイズを表す数値です。転送に当たりファイルはこのサイズで複数のピースに分割されます。最後のひとつだけはこの値より小さくなる場合もありますが、そのほかはすべて同じ大きさになります。ピースのサイズはほぼ常に 2 の累乗で、たいていは 218 = 256 K (BitTorrent バージョン 3.2 以前では 220 = 1 M) がデフォルトです。

pieces の値は 20 の倍数の長さを持つ文字列です。この文字列を長さ 20 で分割すると、それぞれインデックスにより対応付けられる各ピースの SHA1 ハッシュ値になります。

lengthfiles はどちらか一方だけが使われます。キー length が存在するときは単一ファイルのダウンロードであることを意味し、files の場合はディレクトリ内の複数ファイルが対象であることを意味します。

単一ファイルの場合 length はファイルの長さをバイト数で示します。

他のキーとの整合性を保つため、複数のファイルはリスト中に表われる順に連結され、単一のファイルとして扱われます。キー files はこのリストを指します。リストの各要素は次のキーを持つ辞書です。

length
ファイルの長さで単位はバイトです。
path
ファイルのパスに現れるサブディレクトリ名のリストで、リストの最後がそのファイル名です(長さ 0 のリストはエラーになります)。

単一ファイルの場合 name キーはファイル名を指し、複数ファイルの場合はディレクトリ名を指します。

ダウンローダからトラッカへのクエリには 2 通りの方法があります。トラッカは HTTP GET パラメータによって情報を受信し、bencoding 形式で応答を返します。トラッカは自前の Web サーバ機能も備えていることに注目してください。この Web サーバ機能は Apache モジュールとして実装したみたいに立派に動作します。

トラッカへの GET リクエストには以下のキーがあります。

info_hash

メタインフォ・ファイルの info の値である bencoding データから算出した20 バイトの SHA1 ハッシュ値です。これはメタインフォ・ファイルに従属する文字列です。ほとんどの場合エスケープする必要があります。

peer_id

このダウンローダが id として使用する長さ 20 の文字列です。すべてのダウンローダは新規ダウンロードの開始に当たり必ずランダムな id を生成します。この値もやはりほとんどの場合エスケープする必要があります。

ip

このダウンローダが使用する IP アドレス(またはホスト名)でオプションです。オリジン・ダウンローダとトラッカを同一マシン上で動かす場合などに使われます。

port

このダウンローダがリッスンするポート番号です。通常ダウンローダはまず 6881 番のリッスンを試み、使えない場合は 6882番、それもダメなら 6883番という具合に最大 6889 番までのポートを試します。

uploaded

これまでにアップロードした合計量を10進数の文字列で表します。

downloaded

これまでにダウンロードした合計量を10進数の文字列で表します。

left

このダウンローダがダウンロードする残りバイト数を10進数の文字列で表します。レジュームによるダウンロード再開や、ファイルの完全性チェックでエラーが出た場合の再ダウンロードがあるため、この値をファイルサイズと downloaded から算出することはできません。

event

オプションのキーで startedcompleted または stopped のキーを持つ辞書を指します(空の場合はこのキー自体が存在しないものとみなされます)。キーが存在しない場合は定期的に送信するアナウンスメントであることを意味します。started 付きのアナウンスメントは最初のダウンロード開始時に、completed 付きのアナウンスメントはダウンロード完了時に送信します。なお開始時既にファイルが存在する場合 completed は送信しません。ダウンロードを中断する場合は stopped を送信します。

トラッカからのレスポンスは becoding データの辞書です。クエリに失敗した場合、レスポンスのキー failure reason にその理由が普通の文字列としてセットされ、ほかのキーはセットされません。成功したときは次の2つのキーがセットされます。まず interval にはダウンローダが通常のリクエストを続けて送る際、送信から次の送信までに置かなければならない間隔が秒数でセットされます。キー peers は通信可能なピアの情報を保持する辞書のリストです。各辞書はキー peer idip、そして port を保持しており、それぞれピアの ID、IP アドレス(またはホスト名)、ポート番号を指します。なおダウンローダはイベント発生時やもっと多くのピアが必要になったときに、スケジュール外のリクエストを送信することもあるので注意してください。

メタインフォ・ファイルやトラッカのクエリを拡張する場合は、その互換性を確実なものにするため Bram Cohen に連絡を取って進めるようにしてください。

BitTorrent のピア・プロトコルは TCP 上で動作します。動作させる上で特別なソケット・オプションは何も必要ありません。

ピア同士の接続は相互に対称な構造になっています。メッセージはお互いどちらの方向にも同じ形式で送られ、データもやはり両方向で送受信されます。

ピア・プロトコルではメタインフォ・ファイルの 0 から始まるファイルのインデックスを使ってピースを指定します。ピアはピースのダウンロードが終わるとハッシュ値が一致するかどうかを調べ、一致すればそのピースを所持していることを他のすべてのピアにアナウンスします。

ピア同士の接続においてはお互いにチョーク状態かどうか(choke または unchoke)、要求状態にあるかどうか(interested または not interested)を表す2ビットの情報が含まれます。チョーク状態になると、それが解除されるまで一切データは送信されなくなります。チョークの理論と技術的な解説は後ほどおこないます。

接続の一方が interested で、もう一方が非チョーク状態ならば、データの転送が開始されます。要求の状態は常に最新に保たれていなければなりません。あるダウンローダが非チョーク状態のピアに対し要求するものが何もない場合は、チョークせずに要求されたものがないことを通知する必要があります。この機能の厳密な実装には手がかかりますが、これによって非チョーク状態のダウンローダはどのピアがダウンロードを開始したのか即座に知ることが可能になります。

接続は unchoke と not interested の状態で開始されます。

転送が開始されると、ダウンローダは複数のピース要求をいっぺんにキューに入れ TCP パフォーマンスの改善をはかります(パイプライニング)。一方 TCP バッファに書き込みきれなかったピース要求はアプリケーション・レベルのネットワーク・バッファに置かず即座にメモリ上のキューに入れなければなりません。こうすることでダウンローダがチョーク状態に入ったときすぐに切り離すことが可能になります。

ピア通信プロトコルは、ハンドシェイクと、それに続く長さのプリフィクス付きメッセージのエンドレスなストリーム通信により成り立っています。ハンドシェイクは数字の 19 とそれに続く 'BitTorrent protocol' という文字列で始まります。最初の数字は文字列の長さを表わすプリフィクスです。新たなプロトコルを作る場合もこの方式に従ってください。そうすることでわずかな違いでそれぞれを判別できるようになります。

これ以降に述べるプロトコルで送信される整数値はいずれも 4 バイトでバイトオーダはビッグエンディアンです。

固定長のヘッダの次には 8 バイトの予約領域があります。現在リリースれている実装においてこの領域はすべて 0 になっています。たとえばプロトコルの拡張でそのうち3バイトを使いたいというときは、その互換性を確かなものにするため Bram Cohen に連絡を取って進めるようにしてください。

次の部分は 20 バイトの SHA1 ハッシュ値です。これはメタ・インフォファイルの info の値である bencoding データから算出したものです(info_hash としてトラッカに通知されたものと同じですが、ここではエスケープせずにそのままの状態で使用します)。双方が同じ値を送信しない場合、通信は切断されます。唯一の例外はダウンローダが 1 つのポートで複数のファイルをダウンロードしようとしているときで、この場合最初がハッシュ値になっている接続を待ち、同じものがリストの中にみつかると応答を返します。

ダウンローダ・ハッシュ値の次は 20 バイトのピア id です。ピア id はトラッカへのリクエストとして送信されるものと同じで、トラッカの応答のピア一覧にもあるものです。受信側のピア id が送信側が期待する値と異なる場合も接続は提供されます。

以上でハンドシェークは終了です。次に来るのはストリーム切り替えの length プレフィクスとメッセージです。長さゼロのメッセージはキープアライブを意味し、無視されます。キープアライブは通常2分に1度の間隔で送信されますが、予定より早くデータが到着した場合はこれより早いタイミングでタイムアウトを発生させることも可能です。

キープアライブ以外のメッセージはすべてタイプを表す1バイトのデータで始まります。その内容は以下の通り。

  • 0 - choke
  • 1 - unchoke
  • 2 - interested
  • 3 - not interested
  • 4 - have
  • 5 - bitfield
  • 6 - request
  • 7 - piece
  • 8 - cancel

'choke'、'unchoke'、'interested' および 'not interested' の場合ペイロードはありません。

'bitfield' は最初のメッセージとして送信します。ペイロードのビットフィールドはピースのインデックスで、そのダウンローダが送信済みのものは 1、そのほかには0をセットします。提供できるピースがまだ何もないダウンローダはこの 'bitfield' メッセージをスキップしてかまいません。ビットフィールドの最初の1バイトは上位ビットから下位ビットに向かってそれぞれ 0 から 7 の値に対応します。次の1バイトは 8から 15 という具合です。残りのスペアビットにはゼロをセットします。

'have' メッセージのペイロードは1個の数値で、ダウンローダがダウンロードを完了し、ハッシュ値のチェックを終えたことを示す指標です。

'request' メッセージは index、begin、length をペイロードとして持っています。後の2つはバイトオフセットです。length の値は EOF により切り捨てられていない限り2のべき乗になります。現在の実装はすべて 215 となっており、 217 より大きな値で接続を閉じるようになっています。

'cancel' メッセージはのペイロードは 'request' メッセージと同じです。通常はダウンロードの終了間近、「エンドゲーム・モード」において送信されます。ダウンロードの終了が真近になると、ダウンロードが完了したダウンローダは接続を切ってしまうため、最後の数ピースのダウンロードのアクセスが単一のラインに集中し、長く時間がかかってしまいがちです。最後の数ピースの処理を迅速におこなうため、そのダウンローダがダウンロードできなくて保留になっているすべてのリクエストを、そのダウンローダからダウンロードしているすべてのピアに対し送信します。その際効率が低下してしまうことを避けるため、ピースのダウンロードが完了したものについては 'cancel' をすべてのピアに送信します。

'piece' メッセージには index、begin、piece が含まれます。これらは 'request' メッセージにと連動していることに注意してください。choke や unchoke メッセージはす早く送られるのに、転送スピードがすごく遅い場合、期待していないピースが届いてしまうこともあるからです。

ダウンローダは通常各ピースをランダムな順序でダウンロードします。このためピースの全体や一部をどのピアからもらってもいいようになっています。

チョークが必要な理由はいくつかあります。TCP の輻湊回避機能は大量の接続がいっぺんに来た場合、往々にしてうまく働かないためです。またチョークにより各ピアが「お互いさま」的アルゴリズムを使って動作すれば、ダウンロードスピードの安定が実現可能になります。

以下に述べるチョークのアルゴリズムは既に実装されているものです。新たなアルゴリズムを考える場合、ネットワーク全体が新たなアルゴリズムだけで構成されているときと古いアルゴリズムが混在しているとき両方で動くようにしなければなりません。

良いチョーキング・アルゴリズムはいくつもの事柄を同時に監視するようなものでなければなりません。同時に発生する多数のアップロードが適切なパフォーマンスを得られるようにし、細動現象と呼ばれるチョーク、チョーク解除の頻発を回避しなければなりません。また、ダウンロードさせてくれたピアに対しては優遇するようにしなければなりません。さらに時々使用していない接続を試し、現在使用している接続よりもベターな接続がないか探すようにしなくてはなりません。これを楽観的チョーク解除と呼びます。

現在実装済みのチョーク・アルゴリズムでは細動現象を同じ接続先に対し10秒に1度のチョークしか許可しないという単純なアルゴリズムで回避しています。またアップロード先としてチョークを解除する相手ははダウンロードのレートが良く、interested なピア4つまでに制限しています。なお not interested であってもアップロードのレートが良いピアはチョーク解除されますが、interested であってもアップロードに貢献していないピアはチョークされます。またダウンローダが完全なファイルを保持している場合、非チョーク先に対しダウンロードのレートよりもアップロードのレートを優先させるようになっています。

楽観的チョーク解除のために、アップロードのレートにかかわらずチョーク解除されるピアが必ず1つ存在します(そのピアが interested な場合はダウンロードの許可を与える4つのピアのひとつにカウントされます)。楽観的チョーク解除の対象ピアは30秒ごとに切り替わります。ローテーション対象のピアに対しちゃんとしたピースのアップロード機会を与えるため、3回までアップロード開始の機会が与えられるようになっています。

最終更新 2004-03-02 17:19:12

3月 2004
1 2 3 4 5 6 7
8 91011121314
15161718192021
22232425262728
293031    
2月
2004
 4月
2004

BitTorrent protocol specification の日本語訳

XML-Image Letterimage

© 2004-2010, Yasushi Iwata