# リクエストの中身

* **peer id を生成する**
* **info 辞書 の Hashを生成する**
* **portを用意する**
* **アドレスを生成する**
* **Get リクエストでデータ**

実際に、Trackerサーバー とTrackerクライアント の間でやり取 りされるデータの形式について解析していきます。 Tracker はデータを配信している Peer の一覧を管理していま す。以前解説した通り、Torrentではデータをダウンロードする 側もデータの配信にまわるのでした。 Torrent ではこの仕組みを実現するために、Trackerへ自身を登 録する対価として、Peerの一覧を取得できるような仕組みにな っています。

## データ配信に必要なものが入っている

データ配信に必要なものは、配信するデータ、配信するサーバ ーのIPアドレス、配信するサーバーのポート番号、配信する端 末のID、どのデータを配信かるかの情報です。 まず一つ目、配信するデータは、Trackerに初めてアクセスす る時には持っていないものなので、ここでは除外しましょう。

次に必要と思われるのが、IPアドレスです。このアドレスも用 意する必要ありません。TrackerがあなたのIPアドレスを知って いるからです。具体的には、Trackerにアクセスする際に、自身 のIPアドレスをTrackerは知る事ができます。 例えば、Httpサーバーで通信相手のIPアドレスを返すようなプ ログラムは以下のような感じで書けます。

```
{
  HttpServer.bind(address, port).then((io.HttpServer server) {
    server.listen((HttpRequest request) {
      request.response.write(request.connectionInfo.remoteAddress.toString(););
      request.response.close();
    });
  });
}
```

このように、Httpサーバーは、相手のIPアドレスを知っていま す。なので、リクエストに含める必要はなさそうです。 その次に必要と思われるのはポート番号です。他のPeerからの 接続を待ち受けるには、IPアドレスとPort番号が必要です。 Tracker は待ち受けしている Port 番号を IPアドレス のように 知るすべはありません。リクエストとして通知してあげる必要 がありそうです。

最後に、IDが必要です。Peerを識別する情報としてIPアドレス を利用する方法が考えられます。しかし、IPアドレスは複数の 端末で共有している場合や、通信環境によっては同一のIPアド レスを長時間維持するができなかったりします。 そこで、Peerごとに識別子を自身で生成して、それを利用しま す。

もう一つ、必要なものがありました。どのデータをダウンロー ドしたいかといった情報です。Trackerは同一のアドレスで多数 のデータを配信するPeerを管理することがあります。どのデー タを配信してほしいのかを Tracker に通知する必要がありま す。

だいたい、リクエストら必要な情報が見えてきました。具体的 にGetリクエストで使用する値について見ていきましょう。

## Info辞書からIDを生成

まずは、どのデータをダウンロードしたいかを指定するための IDを用意しましょう。 Torrent が扱う全てのデータは衝突しな い固有の識別子を持っています。これは、ひとつの配信データ を複数の Tracker で管理したい場合に有効な方法です。唯一の IDで有るならば、このTrackerで管理しても、関係のないデー タが混ざる事がないからです。このような方法を用いる事で、 Tracker への負荷を分散する事が可能になります。 では、どのように唯一IDを生成するのでしょうか。特定の管理 団体などにIDをもらう必要があるのでしょうか？Torrentでは SHA1 が用いられています。 SHA1 は、全てのデシタルデータに 160bit(20byte) の ID をふ るアルゴリズムです。2の160乗のIDの振る事ができますから、 異なるデータなのに、同じIDを振られる事はありません。

Torrentでは、Info辞書のSHA1をとりIDとして利用します。 Dartでは以下のように書けます。

```
{
  data.Uint8List list = Bencode.encode(file.mMetadata[TorrentFile.KEY_INFO]);
  crypto.SHA1 sha1 = new crypto.SHA1();
  sha1.add(list.toList());
  sha1.close(); //return value is id
}

見ての通り Torrentファイルのなかの Info 辞書の部分のバイナ
リでデータのSHA1をとるだけです。

## 自身のIDを用意する

Info辞書の識別子と同様に、自身のIDも20バイトのバイナリデ
ータを利用します。そして、IDの生成は各Torrentクライアント
行います。IDの生成は、Info辞書のSHA1をとった時のように明
確に生成するルールは存在していません。
他の Torrent クライアントが生成したIDと衝突しない用に注意
し生成する必要があります。
ここでは、「乱数を使う方法」を紹介します。
```

class PeerIdCreator { static math.Random \_random = new math.Random(new DateTime.now().millisecond); static List createPeerid(String id) { List output = new List(20); for (int i = 0; i < 20; i++) { output\[i] = \_random.nextInt(0xFF); } List idAsCode = id.codeUnits; for(int i=0;i<5&\&i\<idAsCode.length;i++) { output\[i+1] = idAsCode\[i]; } return output; }

```
1byte づつ乱数を計算して代入しています。追加機能として、
どのクライアントで生成されたを判別できるように、idの一部
に文字列を追加できるようにしました。

## Portを用意する
Torrent クライアントは、サーバーの機能とクライアントの機
能をもっています。他のTorrentクライアントからの接続を待ち
受けるには、サーバーの機能を立ち上げる必要があります。こ
の時のサーバーのポート番号を用意します。
```

{ HttpServer.bind(address, port).then((io.HttpServer server) { server.listen((HttpRequest request) { request.response.write(request.connectionInfo.remoteAddress.toString();); request.response.close(); }); }); }

```
以前、書いたHttpサーバーのコードで指定したPort番号で良い
です。
実際には、ご家庭ネットワーク環境では、ここで指定したポー
ト番号と、実際に外部から見えているポート番号が異なる場合
があります。このような場合に対処するには、もうひと工夫必
要です。
付録の「なぜなにNat Travarsal」を参照してください。


## アドレスを生成する

だいたい必要な情報は整いました。さっそくアドレスを生成し
てみましょう。
実際には、以下のような情報も追加してアドレスを作成する事
になります。

##### "info_hash"
TorrentファイルのInfo辞書のSHA1

##### "peer_id"
生成した20byteのバイナリデータ

##### "event"
Torrentクライアントり状態を表します。“started”, “stopped”,”completed”
の3つ。それぞれ、データーのダウンロード中である場合は、”started”、
データのダウンロードと配信から抜ける場合は、”stopped”、データのダ
ウンロードを完了した場合は、”completed”が指定されます。

##### "downloaded"
今までダウンロードが完了したバイト数

##### "uploaded"
今までに配信したバイト数

##### "left"
ダウンロードが済んでいないデータのバイト数
これらのデータを結合して、URLを生成するば完成です。
```

String toString() { return scheme + "://" + trackerHost + ":"

* trackerPort.toString() + ""
* path + toHeader();

  }

String toHeader() { return "?" + KEY\_INFO\_HASH + "=" + infoHashValue

* "&" + KEY\_PORT + "=" + port.toString()
* "&" + KEY\_PEER\_ID + "=" + peerID
* "&" + KEY\_EVENT + "=" + event
* "&" + KEY\_UPLOADED + "=" + uploaded.toString()
* "&" + KEY\_DOWNLOADED + "=" + downloaded.toString()
* "&" + KEY\_LEFT + "=" + left.toString();

  }

  \`\`\`

といった感じで書けます。無事URLを生成する事ができましたね。

Kyorohiro work

<http://kyorohiro.strikingly.com>
