Chokeの実装
    アルゴリズムとして定義することで検証可能にする
    PeerInfoクラスを定義する
    UnchokeしたPeerからChokeするPeerを選択する
    ChokeしたPeerから、UnchokeするPeerを選択する
Chokeを実装してみましょう。Torrentクライアントの通信部分やアプリケーションの部分と、アルゴリズムの部分は分離する事が望ましいです。
このアルゴリズムじたいをテスト可能にするためです。アプリケーション層とまぜると、アプリケーションの操作としてテストしなくては検証できません。 通信部分の一部としてしまっては、通信機能としてテストする事になります。通信部分を利用しなくてはテスト出来ない状態になります。
アルゴリズムとして定義する事で、検証が容易になります。

PeerInfoクラスを定義する

Chokeアルゴリズムに必要な要素を考えて、PeerInfoというクラスを定義しました。
PeerInfoには、Peerのステータスの一覧が定義しました。
1
abstract class TorrentClientPeerInfo {
2
static const int STATE_NONE = 0;
3
static const int STATE_ON = 1;
4
static const int STATE_OFF = 2;
5
String ip = "";
6
int port = 0;
7
List<int> get peerId;
8
int get downloadedBytesFromMe;
9
int get uploadedBytesToMe;
10
int get chokedFromMe;
11
int get chokedToMe;
12
int get interestedToMe;
13
int get interestedFromMe;
14
bool get amI;
15
bool get isClose;
16
int get uploadSpeedFromUnchokeFromMe;
17
}
Copied!
1
class TorrentClientPeerInfos {
2
List<TorrentClientPeerInfo> _peerInfos = [];
3
List<TorrentClientPeerInfo> get rawpeerInfos => _peerInfos;
4
int get numOfPeerInfo => _peerInfos.length;
5
6
TorrentClientPeerInfos() {}
7
8
List<TorrentClientPeerInfo> getPeerInfos(Function filter) {
9
List<TorrentClientPeerInfo> t = [];
10
for (TorrentClientPeerInfo x in _peerInfos) {
11
if (filter(x)) {
12
t.add(x);
13
}
14
}
15
return t;
16
}
17
18
void addPeerInfo(TorrentClientPeerInfo info) {
19
_peerInfos.add(info);
20
}
21
}
Copied!
前章で定義したメッセージに対応したものですね。 このListからChokeする、UnchokeするPeerの一覧を返すメソッドを作れば、Choke機能を実装したことになります。

UnchokeしたPeerからChokeするPeerを選択する

1
List<TorrentClientPeerInfo> extractChokePeerFromUnchoke(TorrentClientPeerInfos infos, int maxOfReplace, int maxOfUnchoke) {
2
List<TorrentClientPeerInfo> unchokedPeers = infos.getPeerInfos((TorrentClientPeerInfo info) {
3
return (info.isClose == false && info.chokedFromMe == TorrentClientPeerInfo.STATE_OFF && info.amI == false);
4
});
5
List<TorrentClientPeerInfo> alivePeer = infos.getPeerInfos((TorrentClientPeerInfo info) {
6
return (info.isClose == false && info.amI == false);
7
});
8
9
List<TorrentClientPeerInfo> ret = [];
10
if (alivePeer.length > maxOfUnchoke) {
11
unchokedPeers.sort((TorrentClientPeerInfo x, TorrentClientPeerInfo y) {
12
return x.uploadSpeedFromUnchokeFromMe - y.uploadSpeedFromUnchokeFromMe;
13
});
14
15
int numOfReplace = alivePeer.length - maxOfUnchoke;
16
numOfReplace = ((maxOfReplace < numOfReplace) ? maxOfReplace : numOfReplace);
17
for (int i = 0; i < numOfReplace && i < unchokedPeers.length; i++) {
18
ret.add(unchokedPeers[i]);
19
}
20
}
21
return ret;
22
}
Copied!

ChokeしたPeerから、UnchokeするPeerを選択する

1
List<TorrentClientPeerInfo> extractUnchokePeerFromChoke(TorrentClientPeerInfos infos, int numOfUnchoke) {
2
List<TorrentClientPeerInfo> unchokeInterestedPeers = infos.getPeerInfos((TorrentClientPeerInfo info) {
3
return (info.isClose == false && info.interestedToMe == TorrentClientPeerInfo.STATE_ON && info.chokedFromMe == TorrentClientPeerInfo.STATE_ON && info.amI == false);
4
});
5
List<TorrentClientPeerInfo> unchokeNotInterestedPeers = infos.getPeerInfos((TorrentClientPeerInfo info) {
6
return (info.isClose == false && info.interestedToMe != TorrentClientPeerInfo.STATE_ON && info.chokedFromMe == TorrentClientPeerInfo.STATE_ON && info.amI == false);
7
});
8
unchokeInterestedPeers.shuffle();
9
List<TorrentClientPeerInfo> ret = [];
10
for (int i = 0; i < unchokeInterestedPeers.length && ret.length < numOfUnchoke; i++) {
11
ret.add(unchokeInterestedPeers[i]);
12
}
13
for (int i = 0; i < unchokeNotInterestedPeers.length && ret.length < numOfUnchoke; i++) {
14
ret.add(unchokeNotInterestedPeers[i]);
15
}
16
return ret;
17
}
Copied!

Choke、UnchokeするPeerを選択する

今までに作成したメソッドを合わせことで実現できます。
1
TorrentAIChokeTestResult extractChokeAndUnchoke(TorrentClientPeerInfos infos, int maxUnchoke, int maxReplace) {
2
List<TorrentClientPeerInfo> unchokeFromMePeers = infos.getPeerInfos((TorrentClientPeerInfo info) {
3
return (info.isClose == false && info.chokedFromMe == TorrentClientPeerInfo.STATE_OFF && info.amI == false);
4
});
5
List<TorrentClientPeerInfo> aliveAndNotChokePeer = infos.getPeerInfos((TorrentClientPeerInfo info) {
6
return (info.isClose == false && info.amI == false && info.chokedFromMe != TorrentClientPeerInfo.STATE_OFF);
7
});
8
List<TorrentClientPeerInfo> chokePeers = extractChokePeerFromUnchoke(infos, maxReplace, maxUnchoke);
9
for (TorrentClientPeerInfo info in chokePeers) {
10
aliveAndNotChokePeer.remove(info);
11
}
12
int n = unchokeFromMePeers.length - chokePeers.length;
13
List<TorrentClientPeerInfo> unchokePeers = extractUnchokePeerFromChoke(infos, maxUnchoke - n);
14
for (TorrentClientPeerInfo info in unchokePeers) {
15
aliveAndNotChokePeer.remove(info);
16
}
17
18
TorrentAIChokeTestResult ret = new TorrentAIChokeTestResult();
19
ret.choke.addAll(chokePeers);
20
ret.choke.addAll(aliveAndNotChokePeer);
21
ret.unchoke.addAll(unchokePeers);
22
return ret;
23
}
Copied!
Last modified 3yr ago