/** * Downloads the specified file from a peer that is hosting said file * * @param peer A Socket connected to the peer that is hosting the file * @param start The starting byte of the piece that will be downloaded from this peer * @param end The end of the piece that will be downloaded from this peer, not inclusive * @throws java.io.IOException if an error occurs during the download */ private void downloadFromPeer(Socket peer, int start, int end) throws IOException { if (start >= end) { throw new IllegalStateException( "Start byte (" + start + ") must be less than the end byte (" + end + ")"); } DataInputStream in = new DataInputStream(peer.getInputStream()); PrintWriter out = new PrintWriter(peer.getOutputStream(), true); // Tell peer what file to download and the desired chunk size out.println("<GET download " + _file + " " + _chunkSize + " " + start + " " + end + ">"); // Make sure the chunk size is valid String response = in.readUTF(); switch (response) { case "<GET invalid>": System.err.println("[DownloadFromPeerRunnable] Error: Invalid chunk size"); break; case "<GET begin>": saveFile(in, start, end); _callback.onFinishChunk(_file, true); break; default: throw new UnexpectedResponseException(response); } }
/** * Reads a file from the given InputStream and saves it into the local download directory * * @param in The InputStream from which to read the file * @param start The starting byte of the piece that will be downloaded from this peer * @param end The end byte (exclusive) of the piece that will be downloaded from this peer * @throws java.io.IOException if an error occurs while downloading the file */ private void saveFile(InputStream in, int start, int end) throws IOException { if (start >= end) { throw new IllegalStateException( "Start byte (" + start + ") must be less than the end byte (" + end + ")"); } RandomAccessFile fileOut = null; try { File downloadFile = new File(Client.downloadDir, _file); // Open the file in read/write mode with synchronous content/metadata writing fileOut = new RandomAccessFile(downloadFile, "rws"); fileOut.seek(start); byte[] bytes = new byte[_chunkSize]; int bytesRead; int pos = start; while ((bytesRead = in.read(bytes, 0, _chunkSize)) >= 0 && pos < end) { fileOut.write(bytes, 0, Math.min(bytesRead, end - pos)); pos += bytesRead; } } catch (SocketException e) { System.err.println( "[DownloadFromPeerRunnable] Disconnected from peer at " + _peer.getInetAddress()); _callback.onFinishChunk(_file, false); } finally { if (fileOut != null) { try { fileOut.close(); } catch (IOException e) { e.printStackTrace(); } } } }
/** Run the thread */ @Override public void run() { try { downloadFromPeer(_peer, _start, _end); } catch (IOException e) { e.printStackTrace(); _callback.onFinishChunk(_file, false); } }