From dc00963c083109445cce34975a876a8026fde375 Mon Sep 17 00:00:00 2001 From: binlaab Date: Mon, 27 Apr 2026 09:54:27 +0200 Subject: [PATCH] =?UTF-8?q?empezada=20implementaci=C3=B3n=20peerdl,=20camb?= =?UTF-8?q?iar=20DEFAULT=5FDIRECTORY=5FHOSTNAME=20en=20NanoFiles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nanoFiles/application/NanoFiles.java | 2 +- .../nanoFiles/logic/NFControllerLogicP2P.java | 79 +++++++++++++------ .../nanoFiles/tcp/client/NFConnector.java | 25 ++++-- .../nanoFiles/tcp/message/PeerMessage.java | 42 +++++++--- .../nanoFiles/tcp/message/PeerMessageOps.java | 7 +- .../redes/nanoFiles/tcp/server/NFServer.java | 54 +++++++++++-- .../udp/client/DirectoryConnector.java | 45 ++++++++--- 7 files changed, 195 insertions(+), 59 deletions(-) diff --git a/es/um/redes/nanoFiles/application/NanoFiles.java b/es/um/redes/nanoFiles/application/NanoFiles.java index 8e6c12e..af23276 100644 --- a/es/um/redes/nanoFiles/application/NanoFiles.java +++ b/es/um/redes/nanoFiles/application/NanoFiles.java @@ -12,7 +12,7 @@ public class NanoFiles { * que combine los DNIs de ambos miembros del grupo de prácticas. */ public static final String PROTOCOL_ID = "123456789A"; - private static final String DEFAULT_DIRECTORY_HOSTNAME = "localhost"; + private static final String DEFAULT_DIRECTORY_HOSTNAME = "192.168.126.1"; public static String sharedDirname = DEFAULT_SHARED_DIRNAME; public static FileDatabase db; /** diff --git a/es/um/redes/nanoFiles/logic/NFControllerLogicP2P.java b/es/um/redes/nanoFiles/logic/NFControllerLogicP2P.java index 886e085..ddcd643 100644 --- a/es/um/redes/nanoFiles/logic/NFControllerLogicP2P.java +++ b/es/um/redes/nanoFiles/logic/NFControllerLogicP2P.java @@ -2,16 +2,22 @@ package es.um.redes.nanoFiles.logic; import java.net.InetSocketAddress; import java.net.ServerSocket; +import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.io.IOException; +import java.io.RandomAccessFile; + import es.um.redes.nanoFiles.tcp.client.NFConnector; import es.um.redes.nanoFiles.application.NanoFiles; import es.um.redes.nanoFiles.tcp.server.NFServer; +import es.um.redes.nanoFiles.udp.client.DirectoryConnector; +import es.um.redes.nanoFiles.util.FileDigest; import es.um.redes.nanoFiles.util.FileInfo; +import es.um.redes.nanoFiles.util.FileNameUtil; public class NFControllerLogicP2P { // Servidor TCP local para compartir ficheros con otros peers @@ -159,34 +165,33 @@ public class NFControllerLogicP2P { // TODO: localizar peers con el hash solicitado (o uno concreto) y delegar en // downloadFileFromServers boolean success = false; - LinkedList peersWithFile = new LinkedList<>(); - Map peers = dirLogic.fetchPeerList(); - - LinkedList targets = new LinkedList<>(); - - /* if (targetPeerNickname == "*") { bloqueado de momento - targets.addAll(peers.values()); - } else { */ - targets.add(peers.get(targetPeerNickname)); - // } - - for (InetSocketAddress addr : targets) { + if (targetPeerNickname == "*") { + Map peersWithFile = new HashMap(); try { - NFConnector nfc = new NFConnector(addr); + DirectoryConnector dc = new DirectoryConnector(dirLogic.getDirectoryHostname()); // la verdad que debería poder sacarlo de dirLogic + peersWithFile = dc.searchFilesByHash(targetHashSubstring); + + } catch (IOException e) { e.printStackTrace(); } + success = downloadFileFromServers(peersWithFile.values().iterator().next(), peersWithFile.keySet().iterator().next()); // dios + } else { + try { + InetSocketAddress[] peerAddr = new InetSocketAddress[] {dirLogic.fetchPeerList().get(targetPeerNickname)}; + NFConnector nfc = new NFConnector(peerAddr[0]); FileInfo[] peerFiles = nfc.getFileList(); - // la longitud tiene que ser EXACTAMENTE 1, si es 0 no hay, si es > 1 es ambiguo - // y si resulta que dos peers tienen un mismo subhash sin tener el mismo hash? - // mando que no se ha podido descargar? comparo contra el hash del primero? - FileInfo[] peerFilesFound = FileInfo.lookupHashSubstring(peerFiles, targetHashSubstring); - if (peerFilesFound.length == 1) { - peersWithFile.add(addr); + FileInfo[] found = FileInfo.lookupHashSubstring(peerFiles, targetHashSubstring); + if (found.length > 1) { + System.err.println("The hash substring provided is ambiguous"); + return success; + } else if (found.length == 0) { + System.err.println("The hash substring provided could not be found in peer " + targetPeerNickname); + return success; } + + success = downloadFileFromServers(peerAddr, found[0].fileHash); // voy a darle el hash entero, más fácil que volver a buscarlo } catch (IOException e) { e.printStackTrace(); } + System.out.println("Hemos descargado algo? success = " + success); } - - success = downloadFileFromServers(peersWithFile.toArray(new InetSocketAddress[0]), targetHashSubstring); - return success; } /** @@ -196,7 +201,7 @@ public class NFControllerLogicP2P { * que se conectará * @param targetHashSubstring Subcadena del hash del fichero a descargar */ - protected boolean downloadFileFromServers(InetSocketAddress[] serverAddressList, String targetHashSubstring) { + protected boolean downloadFileFromServers(InetSocketAddress[] serverAddressList, String targetHash) { boolean downloaded = false; if (serverAddressList.length == 0) { @@ -207,14 +212,42 @@ public class NFControllerLogicP2P { // pedido, obtener nombre remoto, reservar nombre local sin colisiones, alternar // descarga de chunks y verificar hash final. Cerrar los sockets al terminar. + + long filesize = -1; + String filename = ""; + NFConnector[] peerConns = new NFConnector[serverAddressList.length]; for (int i = 0; i < serverAddressList.length; i++) { try { NFConnector nfc = new NFConnector(serverAddressList[i]); + if (filesize == -1) { + FileInfo[] files = nfc.getFileList(); + FileInfo fileToDownload = FileInfo.lookupHashSubstring(files, targetHash)[0]; // espero solo un archivo + filesize = fileToDownload.fileSize; + filename = toDisplayPath(FileNameUtil.chooseAvailableName(fileToDownload.fileName)); + } peerConns[i] = nfc; } catch (IOException e) { e.printStackTrace(); } } + + + try (RandomAccessFile raf = new RandomAccessFile(NanoFiles.sharedDirname + "/" + filename, "rw")) { + raf.setLength(filesize); + int chunks = (int) Math.ceil((double) filesize / NFConnector.CHUNK_SIZE); + + for (int i = 0; i < chunks; i++) { + NFConnector nfc = peerConns[i % peerConns.length]; + if (!nfc.downloadChunk(targetHash, i, raf)) { + return false; + } + } + + downloaded = true; + } catch (IOException e) { e.printStackTrace(); } + + downloaded = targetHash.equals(FileDigest.computeFileChecksumString(NanoFiles.sharedDirname + "/" + filename)); + return downloaded; } diff --git a/es/um/redes/nanoFiles/tcp/client/NFConnector.java b/es/um/redes/nanoFiles/tcp/client/NFConnector.java index a1274cc..928e570 100644 --- a/es/um/redes/nanoFiles/tcp/client/NFConnector.java +++ b/es/um/redes/nanoFiles/tcp/client/NFConnector.java @@ -19,7 +19,8 @@ import es.um.redes.nanoFiles.util.FileInfo; public class NFConnector { private Socket socket; private InetSocketAddress serverAddr; - + + public static final int CHUNK_SIZE = 64 * 1024; // 64 kB máx private DataInputStream dis; private DataOutputStream dos; @@ -84,7 +85,9 @@ public class NFConnector { LinkedList filelist = new LinkedList<>(); PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_REQUEST_PEER_FILES); msgOut.writeMessageToOutputStream(dos); + System.out.println("gfl enviado"); PeerMessage msgIn = PeerMessage.readMessageFromInputStream(dis); + System.out.println("gfl leido"); if (msgIn.getOpcode() == PeerMessageOps.OPCODE_PEER_FILE) { boolean last = false; while (!last) { @@ -93,31 +96,41 @@ public class NFConnector { String name = msgIn.getFilenameVal(); FileInfo file = new FileInfo(hash, name, size, null); filelist.add(file); - last = msgIn.getLast(); + last = msgIn.getLast(); + System.out.println("Tenemos otro archivo, last = " + last); if (!last) msgIn = PeerMessage.readMessageFromInputStream(dis); // tengo que ver si puedo hacerlo diferente } } else { return null; } + System.out.println("Nos vamos de gfl"); return filelist.toArray(new FileInfo[0]); } catch (IOException e) { e.printStackTrace(); return null; } } - public byte[] downloadChunk(String hash, int chunkNum) { + public boolean downloadChunk(String hash, int chunkNum, RandomAccessFile raf) { + boolean success = false; try { PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_REQUEST_PEER_DL); msgOut.setFileHash(hash); msgOut.setChunkNum(chunkNum); - msgOut.writeMessageToOutputStream(dos); PeerMessage msgIn = PeerMessage.readMessageFromInputStream(dis); if (msgIn.getOpcode() == PeerMessageOps.OPCODE_PEER_DL) { - return msgIn.getFileData(); + byte[] datos = msgIn.getFileData(); + raf.seek((long) chunkNum * CHUNK_SIZE); // buscamos el trozo que estamos leyendo + raf.write(datos); + success = true; + + } else if (msgIn.getOpcode() == PeerMessageOps.OPCODE_AMBIGUOUS) { + System.err.println("More than one file exists with this hash substring"); + } else if (msgIn.getOpcode() == PeerMessageOps.OPCODE_FILE_NOT_FOUND) { + System.err.println("No file matches the hash substring"); } } catch (IOException e) { e.printStackTrace(); } - return null; + return success; } public InetSocketAddress getServerAddr() { diff --git a/es/um/redes/nanoFiles/tcp/message/PeerMessage.java b/es/um/redes/nanoFiles/tcp/message/PeerMessage.java index ceda086..e65a42c 100644 --- a/es/um/redes/nanoFiles/tcp/message/PeerMessage.java +++ b/es/um/redes/nanoFiles/tcp/message/PeerMessage.java @@ -89,6 +89,7 @@ public class PeerMessage { } public void setFilenameVal(String filenameVal) { + this.filenameLong = (byte) filenameVal.length(); this.filenameVal = filenameVal; } @@ -130,6 +131,8 @@ public class PeerMessage { PeerMessage message = new PeerMessage(opcode); switch (opcode) { case PeerMessageOps.OPCODE_REQUEST_PEER_FILES: + case PeerMessageOps.OPCODE_FILE_NOT_FOUND: + case PeerMessageOps.OPCODE_AMBIGUOUS: case PeerMessageOps.OPCODE_PEER_FILES_ERROR: break; case PeerMessageOps.OPCODE_PEER_FILE: { @@ -137,6 +140,7 @@ public class PeerMessage { byte lastVal = dis.readByte(); if (lastVal == 1) { + System.out.println("rmfis - last = " + last); last = true; } long fileSize = dis.readLong(); @@ -158,19 +162,22 @@ public class PeerMessage { } case PeerMessageOps.OPCODE_REQUEST_PEER_DL: { - // buscar archivo supongo - } - case PeerMessageOps.OPCODE_PEER_DL: { int longitudSubHash = (int) dis.readByte(); byte[] subHash = new byte[longitudSubHash]; dis.readFully(subHash); - - + message.setFileHash(new String(subHash)); + message.setChunkNum(dis.readInt()); + break; + } + + case PeerMessageOps.OPCODE_PEER_DL: { + int length = dis.readInt(); + byte[] datos = new byte[length]; + dis.readFully(datos); + message.setFileData(datos); + break; } - - - default: System.err.println("PeerMessage.readMessageFromInputStream doesn't know how to parse this message opcode: " @@ -193,6 +200,8 @@ public class PeerMessage { System.out.println(opcode); switch (opcode) { case PeerMessageOps.OPCODE_REQUEST_PEER_FILES: + case PeerMessageOps.OPCODE_FILE_NOT_FOUND: + case PeerMessageOps.OPCODE_AMBIGUOUS: case PeerMessageOps.OPCODE_PEER_FILES_ERROR: break; case PeerMessageOps.OPCODE_PEER_FILE: { byte lastVal = 0; @@ -207,9 +216,20 @@ public class PeerMessage { dos.write(filenameVal.getBytes()); break; } - - - + + case PeerMessageOps.OPCODE_REQUEST_PEER_DL: { + byte[] hash = fileHash.getBytes(); + dos.writeByte((byte) hash.length); + dos.write(hash); + dos.writeInt(chunkNum); + break; + } + + case PeerMessageOps.OPCODE_PEER_DL: { + dos.writeInt(fileData.length); + dos.write(fileData); + break; + } default: System.err.println("PeerMessage.writeMessageToOutputStream found unexpected message opcode " + opcode + "(" diff --git a/es/um/redes/nanoFiles/tcp/message/PeerMessageOps.java b/es/um/redes/nanoFiles/tcp/message/PeerMessageOps.java index 698c0bd..91503d7 100644 --- a/es/um/redes/nanoFiles/tcp/message/PeerMessageOps.java +++ b/es/um/redes/nanoFiles/tcp/message/PeerMessageOps.java @@ -20,6 +20,7 @@ public class PeerMessageOps { public static final byte OPCODE_FILE_NOT_FOUND = 5; public static final byte OPCODE_AMBIGUOUS = 6; public static final byte OPCODE_PEER_DL = 7; + public static final byte OPCODE_PEER_DL_ERROR = 8; @@ -36,7 +37,8 @@ public class PeerMessageOps { OPCODE_REQUEST_PEER_DL, OPCODE_FILE_NOT_FOUND, OPCODE_AMBIGUOUS, - OPCODE_PEER_DL + OPCODE_PEER_DL, + OPCODE_PEER_DL_ERROR }; private static final String[] _valid_operations_str = { "INVALID_OPCODE", "REQUEST_PEER_FILES", @@ -45,7 +47,8 @@ public class PeerMessageOps { "REQUEST_PEER_DL", "FILE_NOT_FOUND", "FILE_AMBIGUOUS", - "PEER_DL" + "PEER_DL", + "PEER_DL_ERROR" }; private static Map _operation_to_opcode; diff --git a/es/um/redes/nanoFiles/tcp/server/NFServer.java b/es/um/redes/nanoFiles/tcp/server/NFServer.java index aed5dbf..9f23824 100644 --- a/es/um/redes/nanoFiles/tcp/server/NFServer.java +++ b/es/um/redes/nanoFiles/tcp/server/NFServer.java @@ -3,11 +3,13 @@ package es.um.redes.nanoFiles.tcp.server; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.io.RandomAccessFile; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import es.um.redes.nanoFiles.application.NanoFiles; +import es.um.redes.nanoFiles.tcp.client.NFConnector; import es.um.redes.nanoFiles.tcp.message.PeerMessage; import es.um.redes.nanoFiles.tcp.message.PeerMessageOps; import es.um.redes.nanoFiles.util.FileInfo; @@ -104,7 +106,7 @@ public class NFServer implements Runnable { System.out.println("sent " + PeerMessageOps.opcodeToOperation(msgOut.getOpcode())); } } catch (IOException e) { - // ??????? + e.printStackTrace(); } } @@ -207,24 +209,62 @@ public class NFServer implements Runnable { while(true) { PeerMessage msgIn = PeerMessage.readMessageFromInputStream(dis); + System.out.println("nfserver - " + msgIn.getOpcode()); switch (msgIn.getOpcode()) { case PeerMessageOps.OPCODE_REQUEST_PEER_FILES: - - + System.out.println("hemos llegado a nfserver"); FileInfo[] archivos = NanoFiles.db.getFiles(); for (int i = 0; i < archivos.length; i++) { PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_PEER_FILE); FileInfo archivo = archivos[i]; - + System.out.println("Tenemos una lista de archivos de " + archivos.length); msgOut.setFileHash(archivo.fileHash); msgOut.setFileSize(archivo.fileSize); - msgOut.setFilenameVal(archivo.filePath + archivo.fileName); - msgOut.setFilenameLong((byte)archivo.fileName.length()); + msgOut.setFilenameVal(archivo.fileName); msgOut.setLast(false); - if (i == archivos.length - 1) msgOut.setLast(true); + if (i == archivos.length - 1) { msgOut.setLast(true); System.out.println("Hemos llegado al último archivo"); }; msgOut.writeMessageToOutputStream(dos); } + break; + + case PeerMessageOps.OPCODE_REQUEST_PEER_DL: + String subHash = msgIn.getFileHash(); + int chunkNum = msgIn.getChunkNum(); + FileInfo[] files = FileInfo.lookupHashSubstring(NanoFiles.db.getFiles(), subHash); + + if (files.length == 0) { + PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_FILE_NOT_FOUND); + msgOut.writeMessageToOutputStream(dos); + break; + } else if (files.length > 1) { + PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_AMBIGUOUS); + msgOut.writeMessageToOutputStream(dos); + break; + } + + String path = NanoFiles.db.lookupFilePath(files[0].fileHash); + try (RandomAccessFile raf = new RandomAccessFile(path, "r")) { + long chunk = (long) chunkNum * NFConnector.CHUNK_SIZE; + int bytesALeer = (int) Math.min(NFConnector.CHUNK_SIZE, raf.length() - chunk); + // si quedan menos de CHUNK_SIZE bytes restantes, readFully se quedaría esperando + // a rellenar el buffer, lo cual no va a pasar + + if (bytesALeer > 0) { + byte[] datos = new byte[bytesALeer]; + raf.seek(chunk); + raf.readFully(datos); + + PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_PEER_DL); + msgOut.setFileData(datos); + msgOut.writeMessageToOutputStream(dos); + } + + } catch (IOException e) { + PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_PEER_DL_ERROR); + msgOut.writeMessageToOutputStream(dos); + } + break; } } diff --git a/es/um/redes/nanoFiles/udp/client/DirectoryConnector.java b/es/um/redes/nanoFiles/udp/client/DirectoryConnector.java index 51a4d65..1ee623b 100644 --- a/es/um/redes/nanoFiles/udp/client/DirectoryConnector.java +++ b/es/um/redes/nanoFiles/udp/client/DirectoryConnector.java @@ -7,6 +7,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketTimeoutException; import java.util.Map; +import java.util.Arrays; import java.util.LinkedHashMap; import es.um.redes.nanoFiles.tcp.client.NFConnector; @@ -80,7 +81,7 @@ public class DirectoryConnector { * datagramas al directorio */ directoryAddress = new InetSocketAddress(InetAddress.getByName(hostname), DIRECTORY_PORT); - socket = new DatagramSocket(6767); + socket = new DatagramSocket(); } /** @@ -291,18 +292,19 @@ public class DirectoryConnector { */ // este trozo hay que cambiarlo porque qué cojones + // encima tiene algo mal String ip = null; try { - socket.connect(directoryAddress); - ip = socket.getLocalAddress().getHostAddress(); - socket.disconnect(); - } catch(Exception e) {} + socket.connect(directoryAddress); + ip = socket.getLocalAddress().getHostAddress(); + socket.disconnect(); + } catch (Exception e) {} DirMessage serve = new DirMessage(DirMessageOps.OPERATION_SERVE, NanoFiles.peerNickname, ip, serverPort); byte[] serveBytes = serve.toString().getBytes(); byte[] response = sendAndReceiveDatagrams(serveBytes); String respStr = new String(response, 0, response.length); - DirMessage respServe= DirMessage.fromString(respStr); + DirMessage respServe = DirMessage.fromString(respStr); success = respServe.getOperation().equals(DirMessageOps.OPERATION_SERVE_OK); if (success) { @@ -345,9 +347,34 @@ public class DirectoryConnector { public Map searchFilesByHash(String hashSubstring) { Map results = new LinkedHashMap(); - - - + + Map peers = getPeerList(); + + for (InetSocketAddress addr : peers.values()) { + try { + NFConnector nfc = new NFConnector(addr); + FileInfo[] peerFiles = nfc.getFileList(); + + // la longitud tiene que ser EXACTAMENTE 1, si es 0 no hay, si es > 1 es ambiguo + // y si resulta que dos peers tienen un mismo subhash sin tener el mismo hash? + // mando que no se ha podido descargar? comparo contra el hash del primero? + FileInfo[] peerFilesFound = FileInfo.lookupHashSubstring(peerFiles, hashSubstring); + + for (FileInfo fi : peerFilesFound) { + InetSocketAddress[] peersWithHash = results.getOrDefault(fi.fileHash, null); + + if (peersWithHash == null) { + peersWithHash = new InetSocketAddress[1]; + peersWithHash[0] = addr; + } else { + peersWithHash = Arrays.copyOf(peersWithHash, peersWithHash.length + 1); + peersWithHash[peersWithHash.length - 1] = addr; + } + + results.put(fi.fileHash, peersWithHash); + } + } catch (IOException e) { e.printStackTrace(); } + } return results; }