ã¿ãªããããã«ã¡ã¯ïŒ ãã®èšäºã§ã¯ãBitTorrentã䜿çšããŠããã€ãã®åé¡ã解決ããäºå®ãããå Žåã Btã©ã€ãã©ãªãšã¯äœããã©ã®ããã«åªããŠããã®ãããªãããã念é ã«çœ®ãå¿
èŠãããã®ãââã«ã€ããŠèª¬æããŸãã 次ã«ãåºæ¬æ©èœãšã¡ã€ã³APIã®ãã¢ãšããŠãæãåçŽãªã³ã³ãœãŒã«ãã¬ã³ãã¯ã©ã€ã¢ã³ããå®è£
ããŸãã
BTã®ç¹åŸŽçãªæ©èœ
Btã¯ãJava 8ã®BitTorrentãããã³ã«ã®ææ°ã®ãã«æ©èœå®è£
ã§ã[1] ã æ¢åã®ãªãŒãã³ãœãŒã¹ã®å¯Ÿå¿ç©[2] [3]ãšæ¯èŒããŠãBtã«ã¯æ¬¡ã®å©ç¹ããããŸãã
- æŽç·Žãšæ¡åŒµã容æã«ããã¢ãžã¥ãŒã«èšèšã ãã®ã¢ãŒããã¯ãã£ã¯ãGuice IoCã³ã³ãããšæšæºã®java.util.ServiceLoaderã¡ã«ããºã ã«åºã¥ããŠããŸãã Guiceã¯ãæ°ããã³ã³ããŒãã³ãã®ééçãªè¿œå ãšæšæºãµãŒãã¹ã®åå®çŸ©ãæäŸããŸããServiceLoaderã䜿çšãããšã次ã®ãããªããã€ãã®ã¢ãžã¥ãŒã«ã§æ§æãããã¯ã©ã€ã¢ã³ããç°¡åã«æ§ç¯ã§ããŸãã å¥ã®jarã«ãããŸãã
- ããŒã¿ã¹ãã¬ãŒãžã¡ã«ããºã ãžã®ãã€ã³ãã®æ¬ åŠã æšæºã¹ãã¬ãŒãžã¯ãã¡ã€ã«ã·ã¹ãã ã®ååšãåæãšããŠããŸããã
java.nio.file.Path
ã€ã³ã¿ãŒãã§ãŒã¹ã®äœ¿çšã®ãããã§ã Jimfsãªã©ã®ã¡ã¢ãªå
ãã¡ã€ã«ã·ã¹ãã [4] ã - ç¬èªã®ã¡ãã»ãŒãžã¿ã€ãã䜿çšããæšæºãããã³ã«ã®æ¡åŒµã®å®å
šãµããŒã[5] ãç¹å®ã®ããŒãºã«å¯Ÿå¿ããéæšæºã¯ã©ã€ã¢ã³ããéçºããå Žåã«åœ¹ç«ã€å ŽåããããŸãã
- ç¹ã«ã¡ãã»ãŒãžã®éåä¿¡ã«NIOãšã·ã³ã°ã«ã¹ã¬ããã³ã¢ã䜿çšããŠãããããåŠçããããã¬ã³ãããããã¯ãŒã¯æ¥ç¶ã®æ°ãå€ãå Žåã§ããCPUãšã¡ã¢ãªã®ãããããªã³ããæ¯èŒçäœããããã©ãŒãã³ã¹ãéåžžã«é«éã§ãæ¥ç¶ãšããããã³ã°å
¥åºåïŒã
Btã§ãµããŒããããŠããæ·±å»ãªBitTorrentã¯ã©ã€ã¢ã³ãã®å¿
é ãªãã·ã§ã³ã¯æ¬¡ã®ãšããã§ãã
- ãã¥ãŒãã³ã°ãšæ§æã®è±å¯ãªæ©äŒ[6]
- ã¡ã€ã³ã©ã€ã³DHTãšã®çµ±å[7]
HTTPããã³UDPãã©ãã«ãŒã®ãµããŒãã ãã«ããã©ãã«ãŒããã³ãã©ã€ããŒããã©ãã«ãŒ - ãã«ããã£ã¹ããä»ããããŒã«ã«ãã¢ã®æ€çŽ¢[8]
- é
åžã«é¢ããä»ã®åå è
ãšã®f宎ã«é¢ããæ
å ±ã®äº€æ[9]
- ã»ãã·ã§ã³ããŒãšé察称æå·åã䜿çšãããã©ãã£ãã¯ã®é£èªå[10]
- è€æ°ã®ãã¬ã³ãã®äžŠåããŠã³ããŒã/é
åž
- åã
ã®ãã¡ã€ã«ãéžæããŠããŠã³ããŒããã
- ãããŠæåŸã«ããã°ããããªã³ã¯ã䜿çšããŸãã ãã¬ã³ããããŠã³ããŒãããã«ã¯ããã®äžæã®èå¥åããªã³ã¯ãšããŠæå®ããã ãã§ãã
magnet:?xt=urn:btih:af0d9aa01a9ae123a73802cfa58ccaf355eb19f1
æãåçŽãªã³ãã³ãã©ã€ã³ã¯ã©ã€ã¢ã³ãã®äœæ
äœã®åããæå°éã«æããäžå¿
èŠãªééããé¿ããããã«ãèšäºã®ããã¹ãã§ãããžã§ã¯ãã³ãŒããåçŸããªãã§ãããã«å®æãããããžã§ã¯ããgithub [11]ããããŠã³ããŒãããããšããå§ãããŸãã
ãããžã§ã¯ãæ§æ
䜿ããããããã«ãã¯ã©ã€ã¢ã³ãã®å®è¡å¯èœãã¡ã€ã«ã¯ãã¡ããjarã«ãªããŸããã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ã¹ãšãªãœãŒã¹ãããã³ãã®äŸåé¢ä¿ã¯åäžã®ã¢ãŒã«ã€ãã«åéãããŸãã æ°ããMavenãããžã§ã¯ããäœæããŸããpom.xml㧠ã main()
ã¡ãœãããå®è¡å¯èœãã¡ã€ã«ã®ååãå€éšäŸåé¢ä¿ãããã³ããã€ãã®ãã©ã°ã€ã³ãå«ãã¯ã©ã¹ã宣èšããŸãã
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.github.atomashpolskiy</groupId> <artifactId>bt-cli-demo</artifactId> <version>1.0-SNAPSHOT</version> <name>Bt CLI Launcher</name> <description>Command line BitTorrent client</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <compiler.source>1.8</compiler.source> <compiler.target>1.8</compiler.target> <main.class>bt.cli.CliClient</main.class> <bt-version>1.7</bt-version> <jopts-version>5.0.2</jopts-version> <slf4j-version>1.7.21</slf4j-version> <log4j-version>2.4.1</log4j-version> </properties> <build> <finalName>bt-launcher</finalName> ... </build> <dependencies> <dependency> <groupId>com.github.atomashpolskiy</groupId> <artifactId>bt-core</artifactId> <version>${bt-version}</version> </dependency> <dependency> <groupId>com.github.atomashpolskiy</groupId> <artifactId>bt-http-tracker-client</artifactId> <version>${bt-version}</version> </dependency> <dependency> <groupId>com.github.atomashpolskiy</groupId> <artifactId>bt-dht</artifactId> <version>${bt-version}</version> </dependency> <dependency> <groupId>net.sf.jopt-simple</groupId> <artifactId>jopt-simple</artifactId> <version>${jopts-version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j-version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j-version}</version> </dependency> </dependencies> </project>
äŸåé¢ä¿ãšããŠã3ã€ã®æšæºBtã¢ãžã¥ãŒã«ãæå®ããŸããã
- bt-core ïŒã©ã€ãã©ãªã®ãã³ã¢ãã å€éšäŸåé¢ä¿ã䜿çšããªãåºæ¬æ©èœãå«ãŸããŠããŸã
- bt-http-tracker-client ïŒHTTPãã©ãã«ãŒãšã®çµ±åã¢ãžã¥ãŒã«
- bt-dht ïŒMainline DHTãšã®çµ±åã¢ãžã¥ãŒã«
Log4JïŒSLF4Jãžã®ããªããžãå«ãïŒãšå€ãã®äººã«æãããŠããJOpt Simpleã©ã€ãã©ãª[12]ãå¿
èŠã§ããããã«ãããã³ãã³ãã©ã€ã³åŒæ°ãç°¡åãã€æ¥œããæäœã§ããŸãã
æ§æãã®ã³ã°æ§ælog4j2.xmlãããã«è¿œå ããŸãããããã§ã¯ãã®ããã¹ããæäŸããŸããã ã¢ããªã±ãŒã·ã§ã³ã¯bt.logãšbt-dht.logã® 2ã€ã®ãã¡ã€ã«ã«ãã°ã€ã³ããã ãã§ã ã 2çªç®ã®ãã¡ã€ã«ã«ã¯ãDHTã®æäœã«é¢é£ããã€ãã³ããšã¡ãã»ãŒãžãå«ãŸããŸãããã»ãšãã©ã®å Žåããããã¯ãŠãŒã¶ãŒã«ãšã£ãŠããŸãéèŠã§ã¯ãããŸããã
ãœãŒã¹ã³ãŒã
ããŠããããžã§ã¯ãã®èšå®ã¯çµãããŸãããã³ãŒãã®äœæãå§ããŸãããã 次ã®ã»ã¯ã·ã§ã³ã§ã¯ãããã°ã©ã ã®åŒæ°ãåŠçããŠJREãæ§æããããã«å¿
èŠãªããã€ã³ãã£ã³ã°ãã®èšè¿°ã«æéãå²ããŸãã ãã£ãã¡ãªäººã¯ãã®ã»ã¯ã·ã§ã³ãé£ã°ããŠãããã«ãã¬ã³ãã¯ã©ã€ã¢ã³ãã³ãŒããæžãããšãã§ããŸãã
ãªãã·ã§ã³ãã¢ãŒããããã³JREãã©ã¡ãŒã¿ãŒ
ãã¬ã³ãã¯ã©ã€ã¢ã³ããªã©ã®å°ããªã¢ããªã±ãŒã·ã§ã³ã§ãã䜿çšç®çãšçŸåšã®ç°å¢ã«å¿ããŠãå€æ°ã®æ§æãã©ã¡ãŒã¿ãŒã䜿çšã§ããŸãã ã¢ããªã±ãŒã·ã§ã³ã®ãŠãŒã¶ãŒã«æäŸãããªãã·ã§ã³ã®ãªã¹ããå®çŸ©ããŸãã
- ãã«ãåºå
.torrent
ãã¡ã€ã«ãŸãã¯magnet
ããŠã³ããŒããªã³ã¯ã®æå®- ãã¡ã€ã«ãä¿åãããã£ã¬ã¯ããªãæå®ãã
- 匷å¶ãã©ãã£ãã¯é£èªåã¢ãŒãã®ã¢ã¯ãã£ãåïŒãŠãŒã¶ãŒã®ISPãBitTorrentãã©ãã£ãã¯ãã«ãã/ã·ã§ãŒãã³ã°ããé£èªåã䜿çšããŠããå Žåã§ããã®æ§è³ªãå€æã§ããé«åºŠãªçµ±èšãã©ãã£ãã¯åæããŒã«ã䜿çšããªãå Žåã«äŸ¿å©ã«ãªãå ŽåããããŸãïŒ
- é 次ããŠã³ããŒãã¢ãŒãã®ã¢ã¯ãã£ãåïŒããšãã°ãããŠã³ããŒããšäžŠè¡ããŠã¡ãã£ã¢ãã¡ã€ã«ãåçããããïŒ
- ããŠã³ããŒããããã¡ã€ã«ã®ã€ã³ã¿ã©ã¯ãã£ããªéžæãç¡å¹ã«ããŸãïŒãã®ããããã¬ã³ãã«å«ãŸãããã¹ãŠã®ãã¡ã€ã«ãããŠã³ããŒããããŸããããã¯ããã¡ã€ã«ã®ãªã¹ãã倧ããå Žåã«å¿
èŠã«ãªãããšããããŸãïŒ
- ããŠã³ããŒãå®äºåŸã®ã·ãŒãã¢ãŒãã®ã¢ã¯ãã£ãåïŒããã©ã«ãã§ã¯ãã¯ã©ã€ã¢ã³ãã¯ãã¹ãŠã®ãã¡ã€ã«ãããŠã³ããŒãããããšããã«ã·ã£ããããŠã³ããŸãïŒ
- 䜿çšãããŠããIPã¢ãã¬ã¹ãšããŒãã®è¡šç€ºïŒBitTorrentããã³DHTæ¥ç¶ãšã¯å¥ã«ïŒ
- åé¡ãçºçããå Žåã®ãããã°ã®ããã«ããã詳现ãªãã°ãèŠæ±ããŸã
ãªãã·ã§ã³ã®ãªã¹ããé衚瀺ã«ããåŒæ°ãå¥ã®ã¯ã©ã¹Optionsã«è§£æããŸããããã§ã¯ãããã°ã©ã bt.cli.CliClient.main()
mainã¡ãœããã®åæããŒãžã§ã³ã®ã¿ã瀺ããŸãã
package bt.cli; import joptsimple.OptionException; public class CliClient { private static final Logger LOGGER = LoggerFactory.getLogger(CliClient.class); public static void main(String[] args) { Options options; try { options = Options.parse(args); } catch (OptionException e) { Options.printHelp(System.out); return; } } }
ããã§ãã¢ããªã±ãŒã·ã§ã³ã«äŸ¿å©ãªãã«ãã衚瀺ã§ããŸãïŒ
Option (* = required) Description --------------------- ----------- -?, -h, --help -S, --sequential Download sequentially -a, --all Download all files (file selection will be disabled) * -d, --dir <File> Target download location --dhtport <Integer> Listen on specific port for DHT messages -e, --encrypted Enforce encryption for all connections -f, --file <File> Torrent metainfo file -i, --inetaddr Use specific network address (possible values include IP address literal or hostname) -m, --magnet Magnet URI -p, --port <Integer> Listen on specific port for incoming connections -s, --seed Continue to seed when download is complete --trace Enable trace logging -v, --verbose Enable more verbose logging
ã»ãšãã©ãã¹ãŠã®ãªãã·ã§ã³ã®åŠçã§ã¯ãé£èªåã®æ£ããæäœã®ããã«Log4Jãæ§æããJREãã©ã¡ãŒã¿ãŒãèšå®ããã ãã§ãã main()
ã«ããã€ãã®ãŠãŒãã£ãªãã£ã¡ãœããã®åŒã³åºããè¿œå ããŸãã
configureLogging(options.getLogLevel()); configureSecurity(); registerLog4jShutdownHook();
Log4Jã®ã»ããã¢ããã«é¢é£ããã¡ãœããã¯ãä»ã®ãšããç§ãã¡ã«ãšã£ãŠå€§ããªé¢å¿ã¯ãããŸããã ãã¡ããšãã¡ãã§ã芧ããã ããŸã ã configureSecurity()
ã¡ãœããã¯ããå°ã詳现ã§ãã
å®éãé£èªåãããã³ã«ã¯ã»ãã·ã§ã³ããŒã䜿çšããæå·åã䜿çšããŠãããããæå°æšå¥šãµã€ãºã¯160ãããã§ãã ãœãããŠã§ã¢ã®é
åžãèŠå¶ããã¢ã¡ãªã«ã®æ³åŸïŒã€ãŸããOracle JDKã«å¿
ç¶çã«é¢ä¿ããããšãæå³ããŸãïŒã«ãããšãããã©ã«ãã®æå·åã®æ倧蚱容ããŒãµã€ãºã¯128ããããè¶
ããããšã¯ã§ããŸããã 倧ããªããŒã®äœ¿çšã¯çŠæ¢ãããŠããŸãããããŠãŒã¶ãŒã¯å¿
èŠãªèšå®ãè¡ãããã®æ©äŒããããã¯è§£é€ãããå¿
èŠããããŸãã Btèšå®ã§ã¯ãããŒãµã€ãºã128ã4096ãããã«èšå®ã§ããŸããããã®å Žåãããã©ã«ãã§èšå®ãããæé©ãªå€ã®ãŸãŸã«ããŠãåãJREãèšå®ããŸãã Oracle JREããŒãžã§ã³8u152ãŸã§ã¯ããã®ããã«jarãã¡ã€ã«ãOracleãµã€ãããããŠã³ããŒãã[13] ãåãååã®ãã¡ã€ã«ãã€ã³ã¹ããŒã«æžã¿ã®ãã£ã¹ããªãã¥ãŒã·ã§ã³ã«çœ®ãæããå¿
èŠããããŸããã ããŒãžã§ã³8u152以éãç°å¢å€æ°crypto.policy=unlimited
[14]ãèšå®ããã ãã§åãå¹æãå®çŸã§ããŸãã ããã¯ãŸãã«configureSecurity()
ã¡ãœãããè¡ãããšã§ãã
private static void configureSecurity() {
ãããã£ãŠã劥åãªãã·ã§ã³ãéžæããŸãã
- ãŠãŒã¶ãŒããæ°é®®ãªãJREãæã£ãŠããå Žåããã¹ãŠãããã«åäœããŸãã
- ãŠãŒã¶ãŒããã¹ãŠã®ãã©ãã£ãã¯ã®åŒ·å¶é£èªåãèŠæ±ããŠããªãå ŽåãBtã¯é£èªåã䜿çšããŠãã¢ãšã®æ¥ç¶ã確ç«ããæ©èœãèªåçã«ç¡å¹ã«ããŸãã åæã«ãå¹³ææ¥ç¶ã¯éåžžã©ããæ©èœããŸãã
- JREãå€ããèšå®ãããŠããªãå ŽåããŠãŒã¶ãŒãé£èªåãèŠæ±ãããšãBtã¯ãšã©ãŒã®åŠçãåæ¢ãããŠãŒã¶ãŒã«JREã®èšå®ãæ±ããŸãã
ãµãïŒ Javaããã®åé·ããšè€éãã§æåã§ããã®ãäžæè°ã§ã¯ãããŸããã æåŸã®éšåã«å°éãã...
BTãšã®çµ±å
ãã¬ã³ãã¯ã©ã€ã¢ã³ãã³ãŒãã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒãããã€ãã®ãã«ããŒã¡ãœãããããã³å®è¡ããã¡ãœããã§æ§æãããŸãã ãŸããã³ã³ã¹ãã©ã¯ã¿ãŒãæ€èšããŸãã
private final Options options; private final SessionStatePrinter printer; private final BtClient client; public CliClient(Options options) { this.options = options; this.printer = new SessionStatePrinter(); Config config = buildConfig(options); BtRuntime runtime = BtRuntime.builder(config) .module(buildDHTModule(options)) .autoLoadModules() .build(); Storage storage = new FileSystemStorage(options.getTargetDirectory().toPath()); PieceSelector selector = options.downloadSequentially() ? SequentialSelector.sequential() : RarestFirstSelector.randomizedRarest(); BtClientBuilder clientBuilder = Bt.client(runtime) .storage(storage) .selector(selector); if (!options.shouldDownloadAllFiles()) { CliFileSelector fileSelector = new CliFileSelector(); clientBuilder.fileSelector(fileSelector); runtime.service(IRuntimeLifecycleBinder.class) .onShutdown(fileSelector::shutdown); } clientBuilder.afterTorrentFetched(printer::onTorrentFetched); clientBuilder.afterFilesChosen(printer::onFilesChosen); if (options.getMetainfoFile() != null) { clientBuilder = clientBuilder.torrent(toUrl(options.getMetainfoFile())); } else if (options.getMagnetUri() != null) { clientBuilder = clientBuilder.magnet(options.getMagnetUri()); } else { throw new IllegalStateException("Torrent file or magnet URI is required"); } this.client = clientBuilder.build(); }
ã³ãŒããèŠãŠãå¿
èŠãªèª¬æãè¡ããŸãããã
Config config = buildConfig(options);
buildConfig()
ã¡ãœããã¯ãBt ã©ã³ã¿ã€ã æ§æãäœæããŸãã Rantimeã¯ãããããç¬èªã®ãã¬ã³ããåŠçããŠãã顧客ã®ã³ã³ããã§ãã ã©ã³ã¿ã€ã ã®äž»ãªæ©èœïŒ
- ãã¹ãŠã®é¡§å®¢ã«å
±éã®ãµãŒãã¹ãšæ¡åŒµæ©èœãå«ãåäžã®IoCã³ã³ãããŒã«ã¢ãžã¥ãŒã«ãçµã¿ç«ãŠãŸãã
- æ¥ç¶ããŒã«ãã€ãã³ãã»ã³ã¿ãŒããã©ãã«ãŒããã¢ãã¡ã€ã³ããŒãšå¯Ÿè©±ããã³ã³ããŒãã³ããDHTãµãŒããŒãªã©ã®å
±æãªãœãŒã¹ãæäŸããŸãã
- ã¢ããªã±ãŒã·ã§ã³ã©ã€ããµã€ã¯ã«ç®¡çïŒãµãŒãã¹ã®éå§ãšåæ¢ãã«ã¹ã¿ã ã³ãŒã«ããã¯ã®åŒã³åºãã
åã
ã®ã¯ã©ã€ã¢ã³ãã¯ãããã€ãã®ç¹å®ã®ãã¬ã³ãåºæã®ãªããžã§ã¯ãïŒ ã³ã³ããã¹ã ïŒã«å¯Ÿããå°åã§è»œéã®ã©ãããŒã§ãã ãã®ã¿ã¹ã¯ã¯ãç¹å®ã¿ã€ãã®ãã¬ã³ãïŒ .torrent
ãã¡ã€ã«ãŸãã¯magnet
ãªã³ã¯ïŒã®åŠç段éãé çªã«å®äºãããŠãŒã¶ãŒã«åŠçãéå§ããã³åæ¢ããAPIãæäŸããããšã§ãã
ãããã£ãŠãBtãã¥ãŒãã³ã°ã¯2ã€ã®ã¬ãã«ã§å®è¡ãããŸãã
- ãã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«å
±éã®ãã©ã¡ãŒã¿ãŒãå«ãã©ã³ã¿ã€ã ã®æ§æ ïŒIPã¢ãã¬ã¹ãããŒããå
éšã¿ã¹ã¯ã®èµ·åééãå€éšãšãŒãžã§ã³ãïŒãã©ãã«ãŒããã¢ïŒãšã®çµ±åã¿ã€ã ã¢ãŠããããŸããŸãªå¶éãšå¶éïŒæ¥ç¶æ°ããããã¯ãŒã¯çµç±ã§éä¿¡ãããããŒã¿ãããã¯ã®ãµã€ãºãæ·±ãïŒ I / Oæäœãªã©ã®ãã¥ãŒ
- ç¹å®ã®ãã¬ã³ãã«åºæã®ãã©ã¡ãŒã¿ãŒãå«ãåã
ã®ã¯ã©ã€ã¢ã³ãã®æ§æ ïŒãããã¯ã®éžæãšèªã¿èŸŒã¿ã¢ãŒãïŒæããŸããªãããã¯ã®é 次èªã¿èŸŒã¿ãŸãã¯ã©ã³ãã ãªéžæïŒãã¡ã¿ããŒã¿ãœãŒã¹ïŒ
.torrent
ãã¡ã€ã«ãŸãã¯magnet
ãªã³ã¯ïŒãä¿åãã£ã¬ã¯ããªãããã«ç¶ãã³ãŒã«ããã¯ç¹å®ã®èªã¿èŸŒã¿æ®µéã®å®äºæã«åŒã³åºããŸãã
ã©ã³ã¿ã€ã æ§æãäœæããããã®ã³ãŒããæ€èšããŠãã ããã
private static Config buildConfig(Options options) { Optional<InetAddress> acceptorAddressOverride = getAcceptorAddressOverride(options); Optional<Integer> portOverride = tryGetPort(options.getPort()); return new Config() { @Override public InetAddress getAcceptorAddress() { return acceptorAddressOverride.orElseGet(super::getAcceptorAddress); } @Override public int getAcceptorPort() { return portOverride.orElseGet(super::getAcceptorPort); } @Override public int getNumOfHashingThreads() { return Runtime.getRuntime().availableProcessors(); } @Override public EncryptionPolicy getEncryptionPolicy() { return options.enforceEncryption()? EncryptionPolicy.REQUIRE_ENCRYPTED : EncryptionPolicy.PREFER_PLAINTEXT; } }; } private static Optional<Integer> tryGetPort(Integer port) { if (port == null) { return Optional.empty(); } else if (port < 1024 || port > 65535) { throw new IllegalArgumentException("Invalid port: " + port + "; expected 1024..65535"); } return Optional.of(port); } private static Optional<InetAddress> getAcceptorAddressOverride(Options options) { String inetAddress = options.getInetAddress(); if (inetAddress == null) { return Optional.empty(); } try { return Optional.of(InetAddress.getByName(inetAddress)); } catch (UnknownHostException e) { throw new IllegalArgumentException( "Failed to parse the acceptor's internet address", e); } }
ããã§ããŠãŒã¶ãŒãæå®ãããã©ã¡ãŒã¿ãŒã«åºã¥ããŠãbt.runtime.Configã¯ã©ã¹ã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæããŸãããã®ã¯ã©ã¹ã§ã¯ããŠãŒã¶ãŒãæå®ããå€ïŒååšããå ŽåïŒãŸãã¯ããã©ã«ãå€ãè¿ãããã«ããã€ãã®ã¡ãœãããåå®çŸ©ããŸãã
2ã€ã®ãã©ã¡ãŒã¿ãŒã«æ³šæãã䟡å€ããããŸãã
1ã€ç®ã¯numOfHashingThreads ããŸãã¯æ¢ã«ããŠã³ããŒããããããŒã¿ã®åææ€èšŒãå®è¡ããã¹ã¬ããã®æ°ã§ãïŒåŸæ¥ã®å°éçšèªã§ã¯ãããã·ã¥ããã¯ã©ã€ã¢ã³ãã®åèµ·åæã«å¿
èŠã§ãïŒã ããã©ã«ãã§ã¯ãBtã¯1ã€ã®ã¹ã¬ããã®ã¿ã䜿çšããŸãããæ€èšŒæé ã¯äžŠååã«é©ããŠãããããè€æ°ã®ã¹ã¬ããã䜿çšããã®ãçã«ããªã£ãŠããŸãã ã¹ã¬ããã®æé©ãªæ°ã¯ã [ ; * 2]
[ ; * 2]
ããªããªã åã
ã®ã¹ã¬ããã¯ã次ã®I / Oèªã¿åãæäœã®å®äºãåŸ
æ©ããŠã¢ã€ãã«ç¶æ
ã«ãªãå ŽåããããŸãã
2çªç®ã®ãã©ã¡ãŒã¿ãŒã¯ããã©ãã£ãã¯ã®é£èªåãé©çšããããªã·ãŒã§ãã ããªã·ãŒã¯ããã¢ãšã®æ¥ç¶ã確ç«ãããããã³ã«ã§äœ¿çšããããã®ãã¡4ã€ã®ã¿ããããŸã[15] ïŒ
1ïŒé£èªåãé©çšãããé£èªåã®äœ¿çšãå¿
èŠãšããåæ¥è
ãšååç©ã確ç«ããªãã§ãã ããã
2ïŒããã©ã«ãã§ã¯ããã¡ããã«ãã¬ãŒã³ããã¹ãã䜿çšããããã«æäŸããŸããããã¡ãããå¿
èŠãªå Žåã¯é£èªåããããšã«åæããŸãã
3ïŒããã©ã«ãã§ã¯ãé£èªåã䜿çšããããã«ãã¡ãããæäŸããŸããããã¡ãããå¿
èŠãªå Žåã¯å¹³æã«åæããŸãã
4ïŒåžžã«é£èªåãé©çšãããã¬ãŒã³ããã¹ããå¿
èŠãšãããã¢ãšã®æ¥ç¶ã確ç«ããªãã§ãã ããã
ãã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ã2ã€ã®æãäžè¬çãªããªã·ãŒããéžæããŸãã匷å¶é£èªåãŸãã¯å®ŽäŒã®èŠæ±ã«å¿ããé£èªåã§ãã æåã®ããªã·ãŒã¯åå·çãªãŠãŒã¶ãŒïŒããã³äžæ£ãªISPïŒã«é©ããŠããã2çªç®ã®ããªã·ãŒã¯æ倧æ°ã®ãã¢ãšã®æ¥ç¶ãèš±å¯ããŸãã
BtRuntime runtime = BtRuntime.builder(config) .module(buildDHTModule(options)) .autoLoadModules() .build();
ã©ã³ã¿ã€ã ã®æ§ç¯ã¯ãé垞次ã®2ã€ã«ãªããŸãã
- å¿
èŠãªã¢ãžã¥ãŒã«ã®ãªã¹ããå®çŸ©ããïŒãã¢ã«é¢ããæ
å ±ã®äº€æãããŒã«ã«ãã¢ã®æ€çŽ¢ãªã©ãæšæºã®æ¡åŒµæ©èœã®ç¡å¹åãå«ãïŒã
- ã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ã¹ãã¹ã«ããã¢ãžã¥ãŒã«ã®æ€çŽ¢ãšèµ·åãæå¹ã«ããŸãïŒãã®å Žåããããã¯pom.xmlã§å®£èšãããã¢ãžã¥ãŒã«ã§ãïŒã
ã¡ã€ã³ã¢ãžã¥ãŒã«ã«å ããŠãã¢ããªã±ãŒã·ã§ã³ã«ã¯2ã€ã®æ¡åŒµã¢ãžã¥ãŒã«ããããŸããHTTPãã©ãã«ãŒãšã®çµ±åã¢ãžã¥ãŒã«ãšMainline DHTãšã®çµ±åã¢ãžã¥ãŒã«ã§ãã æåã®ã¢ãžã¥ãŒã«ã¯autoLoadModules()
åŒã³åºãããšã§èªåçã«æ€åºããã³ããŒããããŸãã2çªç®ã®ã¢ãžã¥ãŒã«ã§ã¯éæšæºæ§æãæå®ãããããæåã§åå®çŸ©ããŸãã
private static Module buildDHTModule(Options options) { Optional<Integer> dhtPortOverride = tryGetPort(options.getDhtPort()); return new DHTModule(new DHTConfig() { @Override public int getListeningPort() { return dhtPortOverride.orElseGet(super::getListeningPort); } @Override public boolean shouldUseRouterBootstrap() { return true; } }); }
2ã€ã®ãã©ã¡ãŒã¿ãŒãåå®çŸ©ããŸãã
- DHTãµãŒããŒãçä¿¡ã¡ãã»ãŒãžããªãã¹ã³ããããŒãã
- ããããªãã¯ãDHTã€ã³ãã©ã¹ãã©ã¯ãã£ïŒ
router.bittorrent.com
ãªã©ã®ãããªãã¯ããŒãã¹ãã©ããããŒãïŒã䜿çšããæš©éã ã€ã³ã¿ãŒãããã§ãã¡ã€ã«ãããŠã³ããŒãããã³é
åžãã以å€ã®ç®çã§BitTorrentã䜿çšããå Žåã¯ããã®ãã©ã¡ãŒã¿ãŒãfalse
èšå®ãããŸãŸã«ããŠãç¬èªã®DHTããŒãã®ãªã¹ãã䜿çšããå¿
èŠããããŸãïŒãã¹ãŠã®Btã€ã³ã¹ã¿ã³ã¹ããã®åœ¹å²ãæããããšãã§ããŸãïŒã
Storage storage = new FileSystemStorage(options.getTargetDirectory().toPath()); PieceSelector selector = options.downloadSequentially() ? SequentialSelector.sequential() : RarestFirstSelector.randomizedRarest(); BtClientBuilder clientBuilder = Bt.client(runtime) .storage(storage) .selector(selector);
次ã®ã¹ãããã§ã¯ãããŠã³ããŒããããã¡ã€ã«ãä¿åãããã£ã¬ã¯ããªãæå®ããŸãã åè¿°ã®ããã«ã bt.data.file.FileSystemStorage
ã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ãŒã¯java.nio.file.Path
ã¿ã€ãã®ãã©ã¡ãŒã¿ãŒãåãå
¥ããŸããããã«ãããJimFSãªã©ã®ã¡ã¢ãªãŒå
ãã¡ã€ã«ã·ã¹ãã ãšçµã¿åãããŠäœ¿çšââã§ããŸãã ã©ã€ãã©ãªèªäœã§ã¯ããã®æ©èœã¯ïŒãã¡ã€ã«I / Oã®å®è¡æéãç¯çŽããããã«ïŒçµ±åãã¹ãã§äœ¿çšãããŸããã仮説çã«ã¯ããããšããŸããã¯ãªãŠãŒã¹ã±ãŒã¹ããããããããŸãã[16] ãäŸãã°ïŒ
more
ãŠãŒãã£ãªãã£ã®ç²Ÿç¥ã§ãã³ã³ãœãŒã«ã«ããã¹ããã¡ã€ã«ãçŽæ¥ããŠã³ããŒãããŸãã- ãªã³ã¶ãã©ã€ã§ãã¡ã€ã«ãåçããã¹ãã¬ãŒãžããã€ã¹ã䜿çšããªãã¡ãã£ã¢ãã¬ãŒã€ãŒã
if (!options.shouldDownloadAllFiles()) { CliFileSelector fileSelector = new CliFileSelector(); clientBuilder.fileSelector(fileSelector); runtime.service(IRuntimeLifecycleBinder.class) .onShutdown(fileSelector::shutdown); }
ã¯ã©ã€ã¢ã³ãã®åéãç¶ããŸãã ãã¡ã€ã«ãå€ãããå ŽåããŸãã¯ãŠãŒã¶ãŒããã£ã¹ããªãã¥ãŒã·ã§ã³å
šäœãããŠã³ããŒãããå Žåã«ããã¡ã€ã«éžæã¹ããããã¹ãããããæ©äŒããŠãŒã¶ãŒã«æäŸããŸããã ãã®ãªãã·ã§ã³ãæå®ãããŠããªãå Žåãã¿ãŒããã«ã€ã³ã¿ãŒãã§ãŒã¹ã§åäœããããã«æ¹åä»ããããç¬èªã®ãã¡ã€ã«ã»ã¬ã¯ã¿ãŒå®è£
ãBtã«æäŸããŸãã
public class CliFileSelector extends TorrentFileSelector { private static final String PROMPT_MESSAGE_FORMAT = "Download '%s'? (hit <Enter> or type 'y' to confirm or type 'n' to skip)"; private static final String ILLEGAL_KEYPRESS_WARNING = "*** Invalid key pressed. Please, use only <Enter>, 'y' or 'n' ***"; private AtomicReference<Thread> currentThread; private AtomicBoolean shutdown; public CliFileSelector() { this.currentThread = new AtomicReference<>(null); this.shutdown = new AtomicBoolean(false); } @Override protected SelectionResult select(TorrentFile file) { while (!shutdown.get()) { System.out.println(getPromptMessage(file)); try { switch (readNextCommand(new Scanner(System.in))) { case "": case "y": case "Y": { return SelectionResult.select().build(); } case "n": case "N": { System.out.println("Skipping..."); return SelectionResult.skip(); } default: { System.out.println(ILLEGAL_KEYPRESS_WARNING); } } } catch (IOException e) { throw new RuntimeException(e); } } throw new IllegalStateException("Shutdown"); } private static String getPromptMessage(TorrentFile file) { return String.format(PROMPT_MESSAGE_FORMAT, String.join("/", file.getPathElements())); } private String readNextCommand(Scanner scanner) throws IOException { currentThread.set(Thread.currentThread()); try { return scanner.nextLine().trim(); } finally { currentThread.set(null); } } public void shutdown() { this.shutdown.set(true); Thread currentThread = this.currentThread.get(); if (currentThread != null) { currentThread.interrupt(); } } }
1ã€ã®ã¡ãœããã§ã¯ã©ã¹ãå®è£
ããå¿
èŠããããŸãããã®ã¡ãœããã¯ãåã
ã®ãã¡ã€ã«ããšã«ãããŠã³ããŒãæ¹æ³ãŸãã¯ã¹ãããæ¹æ³ã決å®ããŸãã ãã®å ŽåããŠãŒã¶ãŒãã察話çã«ç®çã®ã¢ã¯ã·ã§ã³ããªã¯ãšã¹ãããŸãã ãŠãŒã¶ãŒãEnterããŒãæŒãããyããå
¥åãããšããã¡ã€ã«ãããŠã³ããŒãããããŠãŒã¶ãŒããnããå
¥åãããšããã¡ã€ã«ã¯ã¹ããããããŸãã
clientBuilder.afterTorrentFetched(printer::onTorrentFetched); clientBuilder.afterFilesChosen(printer::onFilesChosen);
, , :
- (
magnet
-), ( , 20- URI). - .
UI , .
, , , stopWhenDownloaded()
, . , .. , .
if (options.getMetainfoFile() != null) { clientBuilder = clientBuilder.torrent(toUrl(options.getMetainfoFile())); } else if (options.getMagnetUri() != null) { clientBuilder = clientBuilder.magnet(options.getMagnetUri()); } else { throw new IllegalStateException("Torrent file or magnet URI is required"); } this.client = clientBuilder.build();
, .torrent
, magnet
-. java.util.function.Supplier<Torrent>
, (, ).
: ! main()
, .
public static void main(String[] args) throws IOException { Options options; try { options = Options.parse(args); } catch (OptionException e) { Options.printHelp(System.out); return; } configureLogging(options.getLogLevel()); configureSecurity(); registerLog4jShutdownHook(); CliClient client = new CliClient(options); client.start(); }
start()
, startAsync()
. , , â , , â -, ( â 1 ).
:
, .. , , -.
, . SessionStatePrinter , UI. , , .
,
, , , .

System.out InterruptedException, , .
- , :
magnet:?xt=urn:btih:985BAD472E60E763F5C77B13CBE41AE2892604B6
, , public domain. 12 1959-1961 .
ãããã«
, Bt. API BitTorrent , uTorrent, Transmission, Deluge ., , , ..
, : 2 . , . BitTorrent , [17] , Bt.
, BitTorrent . , , , . , Java BitTorrent , .. , Android [18] .
æåŸãŸã§èªãã§ãããŠããããšãïŒ .
åç
§è³æ
[1] https://github.com/atomashpolskiy/bt
[2] https://github.com/mpetazzoni/ttorrent
[3] https://github.com/bitletorg/bitlet
[4] https://github.com/google/jimfs
[5] http://atomashpolskiy.imtqy.com/bt/extension-protocol/
[6] http://atomashpolskiy.imtqy.com/bt/javadoc/latest/bt/runtime/Config.html
[7] https://en.wikipedia.org/wiki/Mainline_DHT
[8] https://en.wikipedia.org/wiki/Local_Peer_Discovery
[9] https://en.wikipedia.org/wiki/Peer_exchange
[10] https://en.wikipedia.org/wiki/BitTorrent_protocol_encryption
[11] https://github.com/atomashpolskiy/bt-cli-demo
[12] https://pholser.imtqy.com/jopt-simple/
[13] http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
[14] http://www.oracle.com/technetwork/java/javase/8u152-relnotes-3850503.html
[15] http://atomashpolskiy.imtqy.com/bt/encryption/
[16] https://github.com/atomashpolskiy/bt/issues/9
[17] http://bittorrent.org/beps/bep_0052.html
[18] https://www.makeuseof.com/tag/8-legal-uses-for-bittorrent-youd-be-surprised/