Java BitTorrent下载torrent由infohash,没有回应geting pieces metadata?

时间:2017-08-13 10:35:23

标签: java bittorrent

我尝试连接对等方并查询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();
}

我的代码有问题吗?为什么我无法获得查询回复?

0 个答案:

没有答案