なぜなにTorrent
  • Cover
  • イントロ
    • はじめに
    • Torrentとは
    • ゴール
  • Torrentファイルを読み込む
    • About
    • Bencode
    • Bencodeの実装
    • TorrentFileの中身
  • Httpサーバーを作成してみる
  • UPnpによるポートマップ
    • UPnPによるポートマップ
    • UPnPの実装
  • Trackerへアクセスしてみる
    • About
    • TrackerはHttpサーバ
    • リクエストの中身
    • レスポンスの中身
    • テスト
  • ダウンロードゲームへ参加してみる
    • About
    • ダウンロードゲーム
    • ブロックデーターの実装
    • 配信用、Peerを作成してみよう
    • 基本戦術
    • Chokeの実装
  • DHTに対応してみる
    • About
    • Tracker無しでPeerを探す
    • KademliaのkBucketを利用している
    • RootingTableを実装してみよう
    • FindNodeでネットワークの構築
    • FindNodeを実装
    • GetPeersでInfoHashに対応するPeerを探す
    • テスト
  • [Dartの基礎]
    • [なぜDart]
    • Hello World
    • Test/Debug
      • Get started with Observatory
Powered by GitBook
On this page
  • Bitfield実装
  • BlockDataの実装
  1. ダウンロードゲームへ参加してみる

ブロックデーターの実装

  • Bitfieldを実装

  • BlockDataを実装

ブロック単位でデータを管理するためのコードを書いてみましょう。

Bitfield実装

Bitfieldを実装していきす。 Bitfield Bool値(0, 1)を持つ任意の長さの配列です。

Torrentの場合だと、1がデータを持っている、0がデータを持っていないという事を表します。

class BitfieldSample {
  List<bool> _data = [];
  BitfieldSample(int length) {
    _data = new List.filled(length, false);
  }

  bool operator [](int idx) => _data[idx];
  void operator []=(int idx, bool value) {
    _data[idx] = value;
  }
  int get length => _data.length;

}

Torrentはこの値をバイト配列として利用するので、変換するメソッドを用意しておきましょう。

class Bitfield {
....
....

  List<int> toBytes() {
    int bytesLengths = _data.length ~/ 8 + (_data.length % 8 == 0 ? 0 : 1);
    Uint8List ret = new Uint8List(bytesLengths);
    for (int i = 0; i < _data.length; i++) {
      if (this[i] == true) {
        ret[i ~/ 8] |= 0x80 >> (7 - (i % 8));
      }
    }
    return ret;
  }
}

こんな感じです。0x80が先頭Bitで、0x01が末Bit端なのが特徴です。

BlockDataの実装

BlockDataで扱うデータは、メモリーに収まらないことがあります。OSのイメージとかだと1GByteをこえます。ファイルとかで扱うと思います。

しかし、テストを書いたりする場合は、メモリーに収まるデータのみを対象としたほうが扱いやすいですし。場合によっては、ファイルではあるけどねクラウド上のファイルだったりします。

ここでは、以下のような、インターフェイスを利用することにします。

abstract class HetimaData {
  async.Future<int> getLength();
  async.Future<WriteResult> write(Object buffer, int start);
  async.Future<ReadResult> read(int offset, int length, {List<int> tmp:null});
}

BlockDataは、Blockごとにデータの状態を管理します。なので、blockごとにデータを所持しているか、所持していないかを判断できるようにします。

class BlockDataSample {
  BitfieldSample _info = null;
  HetimaData _data = null;
  int _blockSize = 0;
  int _fileSize = 0;
  BlockDataSample(int fileSize, int blockSize, HetimaData data) {
    _info = new BitfieldSample(fileSize ~/ blockSize + (fileSize % blockSize == 0 ? 0 : 1));
    _data = data;
    _blockSize = blockSize;
    _fileSize = fileSize;
  }

  bool operator [](int idx) => _info[idx];
  int get length => _info.length;
}

ブロックごとにデータごとにも書き込み、読み込みの機能を追加します。

  Future<WriteResult> writeBlock(int index, List<int> data) async {
    WriteResult ret = await _data.write(data, index * _blockSize);
    _info[index] = true;
    return ret;
  }

  Future<ReadResult> readBlock(int index) async {
    int start = index * _blockSize;
    int end = (start + _blockSize > _fileSize ? _fileSize : start + _blockSize);
    return _data.read(start, end - start);
  }

これで完成です。

PreviousダウンロードゲームNext配信用、Peerを作成してみよう

Last updated 7 years ago