更新 #4: UDP を使用してアナウンス メッセージを送信するためのデモ Java スニペットが追加されました (接続が最初であることを忘れないでください!) 以下の応答を確認してください。
================================================== ==
更新#3:私はそれを機能させることができました.以下に提示されたメソッドdoConnect()はOKです。詳細は以下の私自身の応答にあります.
================================================== ==
私は主に、アナウンス URL のプロトコルが UDP の場合にトラッカーの応答をダウンロードする方法に興味があります。
詳細: これらは、有効な torrent ファイルからのいくつかのアナウンス URL です (最初のものはメインのものです)。
http://tracker.torrentbox.com:2710/announce
udp://elbitz.net:80/announce.php?passkey=362fc69de3402e8ef5794c7ecf7c58d4
udp://tracker.podtropolis.com:2711/announce
プロトコルがHTTPの場合、すべてがうまくいきます。これが私がどのように機能するかです:
String fullUrl = announceURL + "?info_hash=" + this.m_TorrentInfoHashAsURL + .. // i add the params
URL url = new URL(fullUrl);
URLConnection connection = url.openConnection();
InputStream is = connection.getInputStream();
.. //reading the stream
プロトコルが UDP の場合、URL コンストラクターは「java.net.MalformedURLException: unknown protocol: udp」をスローします。
したがって、問題は次のように再開できると思います: UDP プロトコルで URL から resounce をダウンロードするにはどうすればよいですか? (簡単だといいのですが、データグラムのものは表示されません)
更新#1:
私はオンラインでさらに調査を行い、以下に貼り付けられた次の構造にたどり着きました(動作するはずですが、動作しません。つまり、ローカルでは動作しますが、実際のトラッカーでは動作しません)
仕様へのリンク: http://www.bittorrent.org/beps/bep_0015.html
例:これはソケットを作成する方法ですが、有効なトラッカーでは応答として何も返されないため、何かが機能していません:
if full url: udp://elbitz.net:80/announce.php?passkey=362fc69de3402e8ef5794c7ecf7c58d4
this.m_TrackerHost: elbitz.net
this.m_TrackerPort: 80
private DatagramSocket m_WorkingSocket;
private DatagramSocket getWorkingSocket() {
Logger.d(TAG, "getWorkingSocket()");
if(this.m_WorkingSocket==null){
Random rnd = new Random();
for (int i = 0; i < 100; i++) {
try {
int port = 15000 + rnd.nextInt(15000); // [15000-30000)
DatagramSocket result = new DatagramSocket(port);
InetAddress trackerAddress = InetAddress.getByName(this.m_TrackerHost);
result.connect(trackerAddress, this.m_TrackerPort);
this.m_WorkingSocket = result;
} catch (SocketException se) {
Logger.w(TAG, "getWorkingSocket() - port is taken");
} catch (SecurityException se) {
Logger.w(TAG, "getWorkingSocket() - port is blocked?");
} catch (UnknownHostException e) {
Logger.w(TAG, "getWorkingSocket() - unkwnown host?");
}
}
}
return this.m_WorkingSocket;
}
& 今、最初の通信フェーズである doConnect からの完全なコード (次はアナウンス .. 同様のコードがあります)
private boolean doConnect() throws IOException{
Logger.d(TAG, "doConnect()");
DatagramSocket workingSocket = this.getWorkingSocket();
DatagramPacket sendPacket = null, receivePacket = null;
byte[] sendData = null;
byte[] receiveData = null;
int round = 0;
Logger.d(TAG, "doConnect(): first round, timeout: " + this.getTimeoutInMillis(ACTION_ID_CONNECT, round));
while(true) {
if(round==8){
Logger.w(TAG, "doConnect() - failed to connect with tracker, consumed in vain all 8 rounds..");
return false;
}
workingSocket.setSoTimeout(this.getTimeoutInMillis(ACTION_ID_CONNECT, round));
if(receivePacket==null){
/*
Offset Size Name Value
0 32-bit integer action 0 // connect
4 32-bit integer transaction_id
8 64-bit integer connection_id
16 */
receiveData = new byte[16]; //CONNECT: at least 16 bytes
receivePacket = new DatagramPacket(receiveData, receiveData.length);
sendData = this.getConnectRequest();//return byte[] with everything..just like in specs
sendPacket = new DatagramPacket(sendData, sendData.length);
}
try {
Logger.d(TAG, "doConnect() - sending connect data: " + (Arrays.toString(sendData)));
workingSocket.send(sendPacket);
workingSocket.receive(receivePacket);
break;
} catch (SocketTimeoutException ste) {
round ++;
Logger.w(TAG, "doConnect() connect - new round: " + (round+1) + "|timeout: " + this.getTimeoutInMillis(ACTION_ID_CONNECT, round));
continue;
}
}
byte[] connectResponse = receivePacket.getData();
int actionIdFromResponse = Utils.byteArrayToInt(Utils.subArray(connectResponse, 0, 4));
int transactionIdFromResponse = Utils.byteArrayToInt(Utils.subArray(connectResponse, 4, 4));
long connectionIdFromResponse = Utils.byteArrayToLong(Utils.subArray(connectResponse, 8, 8));
if(transactionIdFromResponse!=this.m_TransactionId){
Logger.w(TAG, "doConnect() - received different transactionId");
return false;
}
if(actionIdFromResponse!=ACTION_ID_CONNECT){
Logger.w(TAG, "doConnect() - didnt received ACTION_ID_CONNECT");
return false;
}
//store connectionId
this.m_ConnectionId = connectionIdFromResponse;
return true;
}
問題が残っています..トラッカーからの応答を受信しません(他のURLでも試しました)また、新しい質問:完全なURLに詳細情報が含まれている場合(例:/アナウンス)、elbitz.net、ポート:80でソケットを作成しても問題ありませんか?
アップデート #2
上記のコードは問題なく動作するようです.. Google で、この仕様を実装したトラッカーのリストを見つけました & 出来上がりの応答が発生しました (例: "udp://tracker.openbittorrent.com:80")
新しい質問と仕様はこちら: http://www.bittorrent.org/beps/bep_0015.html - ピアのリストを取得する方法がわかりません?? .. torrent トラッカーへの通常のリクエスト (http による) には、通常のレスポンス (ベンコードされたマップ) と圧縮されたレスポンス (バイナリ形式) の 2 つのケースがありました。それで、ピアのリストは今ですか?
- 仕様から、これはアナウンス応答です:
/* Offset Size Name Value 0 32-bit integer action 1 // announce 4 32-bit integer transaction_id 8 32-bit integer interval 12 32-bit integer leechers 16 32-bit integer seeders 20 + 6 * n 32-bit integer IP address 24 + 6 * n 16-bit integer TCP port 20 + 6 * N */
私のテストから、私は常にフィールドに同じ値を受け取ります:IPアドレスとTCPポート..さらに、リクエストごとに1つの応答を取得する..だから、これはできません!..ピアのリストが必要です!
助けてください!まだ実装していない応答メッセージのタイプはスクレイプとエラーだけです...しかし、誰も興味のある情報を含んでいません(ピア情報:IPとポート)例:スクレイプ
Offset Size Name Value
0 32-bit integer action 2 // scrape
4 32-bit integer transaction_id
8 + 12 * n 32-bit integer seeders
12 + 12 * n 32-bit integer completed
16 + 12 * n 32-bit integer leechers
8 + 12 * N