mirror of
https://github.com/binlaab/nanofiles.git
synced 2026-07-02 14:48:30 +02:00
práctica 3, falta la última parte
This commit is contained in:
55
es/um/redes/nanoFiles/tcp/client/NFConnector.java
Normal file
55
es/um/redes/nanoFiles/tcp/client/NFConnector.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package es.um.redes.nanoFiles.tcp.client;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import es.um.redes.nanoFiles.tcp.message.PeerMessage;
|
||||
import es.um.redes.nanoFiles.tcp.message.PeerMessageOps;
|
||||
import es.um.redes.nanoFiles.util.FileInfo;
|
||||
|
||||
//Esta clase proporciona la funcionalidad necesaria para intercambiar mensajes entre el cliente y el servidor
|
||||
public class NFConnector {
|
||||
private Socket socket;
|
||||
private InetSocketAddress serverAddr;
|
||||
|
||||
|
||||
|
||||
|
||||
public NFConnector(InetSocketAddress fserverAddr) throws UnknownHostException, IOException {
|
||||
serverAddr = fserverAddr;
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Se crea el socket a partir de la dirección del
|
||||
* servidor (IP, puerto). La creación exitosa del socket significa que la
|
||||
* conexión TCP ha sido establecida.
|
||||
*/
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Se crean los DataInputStream/DataOutputStream a
|
||||
* partir de los streams de entrada/salida del socket creado. Se usarán para
|
||||
* enviar (dos) y recibir (dis) datos del servidor.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void test() {
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Enviar entero cualquiera a través del socket y
|
||||
* después recibir otro entero, comprobando que se trata del mismo valor.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public InetSocketAddress getServerAddr() {
|
||||
return serverAddr;
|
||||
}
|
||||
|
||||
}
|
||||
103
es/um/redes/nanoFiles/tcp/message/PeerMessage.java
Normal file
103
es/um/redes/nanoFiles/tcp/message/PeerMessage.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package es.um.redes.nanoFiles.tcp.message;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import es.um.redes.nanoFiles.util.FileInfo;
|
||||
|
||||
public class PeerMessage {
|
||||
|
||||
|
||||
|
||||
|
||||
private byte opcode;
|
||||
|
||||
/*
|
||||
* TODO: (Boletín MensajesBinarios) Añadir atributos u otros constructores
|
||||
* específicos para crear mensajes con otros campos, según sea necesario
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
public PeerMessage() {
|
||||
opcode = PeerMessageOps.OPCODE_INVALID_CODE;
|
||||
}
|
||||
|
||||
public PeerMessage(byte op) {
|
||||
opcode = op;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: (Boletín MensajesBinarios) Crear métodos getter y setter para obtener
|
||||
* los valores de los atributos de un mensaje. Se aconseja incluir código que
|
||||
* compruebe que no se modifica/obtiene el valor de un campo (atributo) que no
|
||||
* esté definido para el tipo de mensaje dado por "operation".
|
||||
*/
|
||||
public byte getOpcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Método de clase para parsear los campos de un mensaje y construir el objeto
|
||||
* DirMessage que contiene los datos del mensaje recibido
|
||||
*
|
||||
* @param data El array de bytes recibido
|
||||
* @return Un objeto de esta clase cuyos atributos contienen los datos del
|
||||
* mensaje recibido.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static PeerMessage readMessageFromInputStream(DataInputStream dis) throws IOException {
|
||||
/*
|
||||
* TODO: (Boletín MensajesBinarios) En función del tipo de mensaje, leer del
|
||||
* socket a través del "dis" el resto de campos para ir extrayendo con los
|
||||
* valores y establecer los atributos del un objeto DirMessage que contendrá
|
||||
* toda la información del mensaje, y que será devuelto como resultado. NOTA:
|
||||
* Usar dis.readFully para leer un array de bytes, dis.readInt para leer un
|
||||
* entero, etc.
|
||||
*/
|
||||
PeerMessage message = new PeerMessage();
|
||||
byte opcode = dis.readByte();
|
||||
switch (opcode) {
|
||||
|
||||
|
||||
|
||||
default:
|
||||
System.err.println("PeerMessage.readMessageFromInputStream doesn't know how to parse this message opcode: "
|
||||
+ PeerMessageOps.opcodeToOperation(opcode));
|
||||
System.exit(-1);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
public void writeMessageToOutputStream(DataOutputStream dos) throws IOException {
|
||||
/*
|
||||
* TODO (Boletín MensajesBinarios): Escribir los bytes en los que se codifica el
|
||||
* mensaje en el socket a través del "dos", teniendo en cuenta opcode del
|
||||
* mensaje del que se trata y los campos relevantes en cada caso. NOTA: Usar
|
||||
* dos.write para leer un array de bytes, dos.writeInt para escribir un entero,
|
||||
* etc.
|
||||
*/
|
||||
|
||||
dos.writeByte(opcode);
|
||||
switch (opcode) {
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
System.err.println("PeerMessage.writeMessageToOutputStream found unexpected message opcode " + opcode + "("
|
||||
+ PeerMessageOps.opcodeToOperation(opcode) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
60
es/um/redes/nanoFiles/tcp/message/PeerMessageOps.java
Normal file
60
es/um/redes/nanoFiles/tcp/message/PeerMessageOps.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package es.um.redes.nanoFiles.tcp.message;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class PeerMessageOps {
|
||||
|
||||
public static final byte OPCODE_INVALID_CODE = 0;
|
||||
|
||||
/*
|
||||
* TODO: (Boletín MensajesBinarios) Añadir aquí todas las constantes que definen
|
||||
* los diferentes tipos de mensajes del protocolo de comunicación con un par
|
||||
* servidor de ficheros (valores posibles del campo "operation").
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* TODO: (Boletín MensajesBinarios) Definir constantes con nuevos opcodes de
|
||||
* mensajes definidos anteriormente, añadirlos al array "valid_opcodes" y añadir
|
||||
* su representación textual a "valid_operations_str" EN EL MISMO ORDEN.
|
||||
*/
|
||||
private static final Byte[] _valid_opcodes = { OPCODE_INVALID_CODE,
|
||||
|
||||
|
||||
|
||||
};
|
||||
private static final String[] _valid_operations_str = { "INVALID_OPCODE",
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
private static Map<String, Byte> _operation_to_opcode;
|
||||
private static Map<Byte, String> _opcode_to_operation;
|
||||
|
||||
static {
|
||||
_operation_to_opcode = new TreeMap<>();
|
||||
_opcode_to_operation = new TreeMap<>();
|
||||
for (int i = 0; i < _valid_operations_str.length; ++i) {
|
||||
_operation_to_opcode.put(_valid_operations_str[i].toLowerCase(), _valid_opcodes[i]);
|
||||
_opcode_to_operation.put(_valid_opcodes[i], _valid_operations_str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforma una cadena en el opcode correspondiente
|
||||
*/
|
||||
protected static byte operationToOpcode(String opStr) {
|
||||
return _operation_to_opcode.getOrDefault(opStr.toLowerCase(), OPCODE_INVALID_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforma un opcode en la cadena correspondiente
|
||||
*/
|
||||
public static String opcodeToOperation(byte opcode) {
|
||||
return _opcode_to_operation.getOrDefault(opcode, null);
|
||||
}
|
||||
}
|
||||
139
es/um/redes/nanoFiles/tcp/server/NFServer.java
Normal file
139
es/um/redes/nanoFiles/tcp/server/NFServer.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package es.um.redes.nanoFiles.tcp.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
|
||||
|
||||
|
||||
public class NFServer implements Runnable {
|
||||
|
||||
public static final int PORT = 10000;
|
||||
|
||||
|
||||
|
||||
private ServerSocket serverSocket = null;
|
||||
|
||||
public NFServer() throws IOException {
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Crear una direción de socket a partir del puerto
|
||||
* especificado (PORT)
|
||||
*/
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Crear un socket servidor y ligarlo a la dirección
|
||||
* de socket anterior
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Método para ejecutar el servidor de ficheros en primer plano. Sólo es capaz
|
||||
* de atender una conexión de un cliente. Una vez se lanza, ya no es posible
|
||||
* interactuar con la aplicación.
|
||||
*
|
||||
*/
|
||||
public void test() {
|
||||
if (serverSocket == null || !serverSocket.isBound()) {
|
||||
System.err.println(
|
||||
"[fileServerTestMode] Failed to run file server, server socket is null or not bound to any port");
|
||||
return;
|
||||
} else {
|
||||
System.out
|
||||
.println("[fileServerTestMode] NFServer running on " + serverSocket.getLocalSocketAddress() + ".");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Usar el socket servidor para esperar conexiones de
|
||||
* otros peers que soliciten descargar ficheros.
|
||||
*/
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Tras aceptar la conexión con un peer cliente, la
|
||||
* comunicación con dicho cliente para servir los ficheros solicitados se debe
|
||||
* implementar en el método serveFilesToClient, al cual hay que pasarle el
|
||||
* socket devuelto por accept.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Método que ejecuta el hilo principal del servidor en segundo plano, esperando
|
||||
* conexiones de clientes.
|
||||
*
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Usar el socket servidor para esperar conexiones de
|
||||
* otros peers que soliciten descargar ficheros
|
||||
*/
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Al establecerse la conexión con un peer, la
|
||||
* comunicación con dicho cliente se hace en el método
|
||||
* serveFilesToClient(socket), al cual hay que pasarle el socket devuelto por
|
||||
* accept
|
||||
*/
|
||||
/*
|
||||
* TODO: (Boletín TCPConcurrente) Crear un hilo nuevo de la clase
|
||||
* NFServerThread, que llevará a cabo la comunicación con el cliente que se
|
||||
* acaba de conectar, mientras este hilo vuelve a quedar a la escucha de
|
||||
* conexiones de nuevos clientes (para soportar múltiples clientes). Si este
|
||||
* hilo es el que se encarga de atender al cliente conectado, no podremos tener
|
||||
* más de un cliente conectado a este servidor.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Añadir métodos a esta clase para: 1) Arrancar el
|
||||
* servidor en un hilo nuevo que se ejecutará en segundo plano 2) Detener el
|
||||
* servidor (stopserver) 3) Obtener el puerto de escucha del servidor etc.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Método de clase que implementa el extremo del servidor del protocolo de
|
||||
* transferencia de ficheros entre pares.
|
||||
*
|
||||
* @param socket El socket para la comunicación con un cliente que desea
|
||||
* descargar ficheros.
|
||||
*/
|
||||
public static void serveFilesToClient(Socket socket) {
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Crear dis/dos a partir del socket
|
||||
*/
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Mientras el cliente esté conectado, leer mensajes
|
||||
* de socket, convertirlo a un objeto PeerMessage y luego actuar en función del
|
||||
* tipo de mensaje recibido, enviando los correspondientes mensajes de
|
||||
* respuesta.
|
||||
*/
|
||||
/*
|
||||
* TODO: (Boletín SocketsTCP) Para servir un fichero, hay que localizarlo a
|
||||
* partir de su hash (o subcadena) en nuestra base de datos de ficheros
|
||||
* compartidos. Los ficheros compartidos se pueden obtener con
|
||||
* NanoFiles.db.getFiles(). Los métodos lookupHashSubstring y
|
||||
* lookupFilenameSubstring de la clase FileInfo son útiles para buscar ficheros
|
||||
* coincidentes con una subcadena dada del hash o del nombre del fichero. El
|
||||
* método lookupFilePath() de FileDatabase devuelve la ruta al fichero a partir
|
||||
* de su hash completo.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
16
es/um/redes/nanoFiles/tcp/server/NFServerThread.java
Normal file
16
es/um/redes/nanoFiles/tcp/server/NFServerThread.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package es.um.redes.nanoFiles.tcp.server;
|
||||
|
||||
import java.net.Socket;
|
||||
|
||||
public class NFServerThread extends Thread {
|
||||
/*
|
||||
* TODO: Esta clase modela los hilos que son creados desde NFServer y cada uno
|
||||
* de los cuales simplemente se encarga de invocar a
|
||||
* NFServer.serveFilesToClient con el socket retornado por el método accept
|
||||
* (un socket distinto para "conversar" con un cliente)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user