public void read(String filename) throws IOException {

        int i = 0, count = 0;
        HashMap<Integer, LinkedList<String>> chunkList = null;

        while (true) {

            /* This is the IP of the node from which to request the chunk list. */
            InetAddress ip = nodeList[i].getNodeIp();

            try {

                Socket readSocket = new Socket();

                /* Read request. */
                ControlMessage readRequest = new ControlMessage('e', ip, filename);

                /* Get the list of nodes that have chunks of the file. */
                InetSocketAddress endpoint = new InetSocketAddress(ip, clusterPort);

                readSocket.connect(endpoint, 1000);

                ObjectInputStream ois = new ObjectInputStream(readSocket.getInputStream());
                ObjectOutputStream oos = new ObjectOutputStream(readSocket.getOutputStream());

                chunkList = (HashMap<Integer, LinkedList<String>>) communicate(oos, ois, readRequest);

                Thread[] readers = new Thread[chunkList.size()];

                Chunk[] chunks = new Chunk[chunkList.size()];

                int j = 0;

                /* For each node that has the chunk, start a AetherFileReader thread. */
                for (Map.Entry<Integer, LinkedList<String>> entry : chunkList.entrySet()) {

                    chunks[j] = null;

                    AetherFileReader fileReader = new AetherFileReader(filename, entry.getKey(), clusterPort, myIp, chunks[j], entry.getValue());
                    readers[j] = new Thread(fileReader);

                    readers[j].start();

                    j++;

                }

                assembleChunks(chunks, readers, filename);
                break;

            } catch (SocketTimeoutException e) {

                if (i == K && ++count == MAX_RETRIES) {
                    throw e;
                } else {
                    i++;
                }

                e.printStackTrace();

            } catch (IOException e) {

                throw e;

            } catch (InterruptedException e) {

                System.out.println("Thread was interrupted. Could not assemble chunks");
                e.printStackTrace();

            }

        }
    }