我尝试连接对等方并查询torrent的信息。 我可以建立tcp连接,并通过响应发送握手,但是当我尝试查询片段数据时,没有来自对等体的响应。
这是我的代码:
public class TorrentTransaction {
private ArrayBlockingQueue<Peer> peers;
private int BLOCK = 16384;
private final int EXTENDED = 20;
private boolean isRequest = false;
private ExecutorService service;
private byte[] handshakePrefix = {
19, 66, 105, 116, 84, 111, 114, 114, 101, 110, 116, 32, 112, 114,
111, 116, 111, 99, 111, 108, 0, 0, 0, 0, 0, 16, 0, 1,
};
public TorrentTransaction(int maxPeers) throws IOException {
this.peers = new ArrayBlockingQueue<>(maxPeers);
this.service = Executors.newCachedThreadPool();
}
private class Transaction implements Runnable {
private Peer peer;
private InputStream input;
private OutputStream output;
private Transaction(Peer peer) {
this.peer = peer;
}
@Override
public void run() {
try {
getTorrentInfo(peer);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
if (output != null) {
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void getTorrentInfo(Peer peer) throws Exception {
Socket socket;
ByteBuffer data = ByteBuffer.allocate(BLOCK);
ByteBuffer pieces = null;
int utMetadata, metadataSize = 0, piecesNum = 0;
socket = establishConn(peer.getIp(), peer.getPort());
socket.setSoTimeout(1000 * 15);
input = socket.getInputStream();
output = socket.getOutputStream();
if (sendHandShake(socket, peer.getInfoHash(), peer.getPeerId()) &&
read(socket, data, 0, 68) && onHandShake(data.array()) &&
sendExtHandshake(socket)) {
while (true) {
int length = readMessage(socket, data);
System.out.println(new String(data.array()));
if (length == 0) {
continue;
}
byte msgType = data.get();
switch (msgType) {
case EXTENDED:
byte extendedID = data.get();
byte[] payload = data.array();
if (extendedID == 0) {
if (pieces != null) {
break;
}
byte[] response = new byte[length];
data.get(response);
Map<String, BEValue> r = BDecoder.bdecode(response).getMap();
metadataSize = r.get("metadata_size").getInt();
utMetadata = r.get("m").getMap().get("ut_metadata").getInt();
piecesNum = metadataSize / BLOCK;
if (metadataSize % BLOCK != 0) {
piecesNum++;
}
pieces = ByteBuffer.allocate(metadataSize);
requestPieces(socket, utMetadata, metadataSize, piecesNum);
data.clear();
continue;
}
if (pieces == null) {
continue;
}
Map<String, BEValue> d = BDecoder.bdecode(payload).getMap();
if (d.get("msg_type").getInt() != 1) {
return;
}
int piece = d.get("piece").getInt();
int index = 0;
int pieceLen = length - 2 - index;
if ((piece != piecesNum - 1 && pieceLen != BLOCK) ||
(piece == piecesNum - 1 && pieceLen != metadataSize % BLOCK)) {
break;
}
pieces.put(payload, index, payload.length);
if (isDone(pieces)) {
byte[] metadataInfo = pieces.array();
if (!Arrays.equals(metadataInfo, peer.getInfoHash())) {
break;
}
}
break;
default:
data.clear();
}
}
}
}
private boolean isDone(ByteBuffer pieces) {
return pieces.array().length != 0;
}
private void requestPieces(Socket socket, int utMetadata, int metadataSize, int piecesNum) throws IOException {
for (int i = 0; i < piecesNum; i++) {
Map<String, BEValue> param = new HashMap<>();
param.put("msg_type", new BEValue(0));
param.put("piece", new BEValue(i));
byte[] msg = BEncoder.bencode(param).array();
byte[] buffer = new byte[msg.length + 2];
buffer[0] = EXTENDED;
buffer[1] = (byte) utMetadata;
System.arraycopy(msg, 0, buffer, 2, msg.length);
output.write(buffer);
buffer = null;
}
isRequest = true;
}
private Socket establishConn(String host, int port) throws Exception {
System.out.println(host + " " + port);
if (port < 1 || port > 65535) {
throw new Exception("Port is invalid !");
}
Socket socket = new Socket(host, port);
socket.setSoTimeout(1000 * 15);
return socket;
}
private int readMessage(Socket socket, ByteBuffer buffer) throws Exception {
if (isRequest) {
read(socket, buffer);
FileUtils.writeByteArrayToFile(new File("response00"), buffer.array());
System.exit(2);
return buffer.limit();
}
byte[] data = new byte[4];
read(socket, data, 0, data.length);
int length = 0;
for (byte b : data) {
length += b & 0xff;
}
if (length == 0) {
throw new SocketException("length should't 0 !");
}
read(socket, buffer);
return length;
}
private boolean read(Socket socket, ByteBuffer data) throws IOException {
read(socket, data, 0, data.limit());
return true;
}
private boolean read(Socket socket, ByteBuffer data, int off, int length) throws IOException {
input.read(data.array(), off, length);
return true;
}
private boolean read(Socket socket, byte[] data, int off, int length) throws IOException {
input.read(data, off, length);
return true;
}
private boolean sendHandShake(Socket socket, byte[] infoHash, byte[] randomStr) throws IOException {
byte[] data = new byte[68];
System.arraycopy(handshakePrefix, 0, data, 0, handshakePrefix.length);
System.arraycopy(infoHash, 0, data, handshakePrefix.length, infoHash.length);
System.arraycopy(randomStr, 0, data, handshakePrefix.length + infoHash.length, randomStr.length);
output.write(data);
return true;
}
private boolean onHandShake(byte[] data) {
System.out.println(new String(data));
for (int i = 0; i < 20; i++) {
if (data[i] != handshakePrefix[i]) {
return false;
}
}
return (data[25] & 0x10) != 0;
}
private boolean sendExtHandshake(Socket socket) throws IOException {
Map<String, BEValue> map = new HashMap<>();
Map<String, BEValue> param = new HashMap<>();
param.put("ut_metadata", new BEValue(1));
map.put("m", new BEValue(param));
output.write(BEncoder.bencode(map).array());
return true;
}
}
public void run() {
Thread tcp = new Thread(() -> {
while (true) {
try {
Peer peer = peers.take();
service.execute(new Transaction(peer));
} catch (Exception e) {
e.printStackTrace();
}
}
});
tcp.start();
}
public void addPeer(Peer peer) {
System.out.println("add Peer : " + peer.getIp());
peers.add(peer);
}
这是主要的:
public static void main(String[] args) throws IOException {
TorrentTransaction transaction = new TorrentTransaction(22);
byte[] infoHash = {16, (byte) 190, (byte) 236, 84, 103, (byte) 129, (byte) 209, (byte) 161, (byte) 153, (byte) 148, (byte) 214, (byte) 188, 94, (byte) 200, 127, 70, (byte) 152, (byte) 193, 31, (byte) 128};
transaction.addPeer(new Peer("83.69.244.187", 63094, infoHash, CommonUtils.randomBytes(20)));
transaction.run();
}
我的代码有问题吗?为什么我无法获得查询回复?