mirror of
https://github.com/binlaab/nanofiles.git
synced 2026-07-01 18:06:29 +02:00
242 lines
7.7 KiB
Java
242 lines
7.7 KiB
Java
package es.um.redes.nanoFiles.tcp.server;
|
|
|
|
import java.io.DataInputStream;
|
|
import java.io.DataOutputStream;
|
|
import java.io.IOException;
|
|
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.message.PeerMessage;
|
|
import es.um.redes.nanoFiles.tcp.message.PeerMessageOps;
|
|
import es.um.redes.nanoFiles.util.FileInfo;
|
|
|
|
|
|
|
|
|
|
public class NFServer implements Runnable {
|
|
|
|
public static final int PORT = 10000;
|
|
|
|
private NFServerState state = new NFServerState();
|
|
|
|
private ServerSocket serverSocket = null;
|
|
|
|
public ServerSocket getServerSocket() {
|
|
return serverSocket;
|
|
}
|
|
|
|
public NFServer() throws IOException {
|
|
/*
|
|
* done: (Boletín SocketsTCP) Crear una direción de socket a partir del puerto
|
|
* especificado (PORT)
|
|
*/
|
|
/*
|
|
* done: (Boletín SocketsTCP) Crear un socket servidor y ligarlo a la dirección
|
|
* de socket anterior
|
|
*/
|
|
InetSocketAddress serverSocketAddress = new InetSocketAddress(PORT);
|
|
serverSocket = new ServerSocket();
|
|
serverSocket.bind(serverSocketAddress);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
/*
|
|
* done: (Boletín SocketsTCP) Usar el socket servidor para esperar conexiones de
|
|
* otros peers que soliciten descargar ficheros.
|
|
*/
|
|
/*
|
|
* done: (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.
|
|
*/
|
|
boolean connectionOk = false;
|
|
Socket socket = null;
|
|
try {
|
|
socket = serverSocket.accept();
|
|
connectionOk = true;
|
|
} catch (IOException e) {
|
|
// conn refused
|
|
}
|
|
|
|
if (connectionOk) {
|
|
System.out.println("accepted");
|
|
try {
|
|
DataInputStream dis = new DataInputStream(socket.getInputStream());
|
|
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
|
|
|
|
/* int intNumber = dis.readInt();
|
|
System.out.println("received " + intNumber);
|
|
|
|
int newInt = intNumber + 1;
|
|
dos.writeInt(newInt);
|
|
System.out.println("sent " + newInt); */
|
|
|
|
PeerMessage msgIn = PeerMessage.readMessageFromInputStream(dis);
|
|
System.out.println("received " + msgIn.getOpcode() + " " + PeerMessageOps.opcodeToOperation(msgIn.getOpcode()));
|
|
|
|
if (msgIn.getOpcode() == PeerMessageOps.OPCODE_REQUEST_PEER_FILES) {
|
|
PeerMessage msgOut = new PeerMessage(PeerMessageOps.OPCODE_PEER_FILE);
|
|
msgOut.setLast(true);
|
|
msgOut.setFileSize(62);
|
|
msgOut.setFileHash("abcdefghijklmnoprqstuvwxyzaaaaaaaaaaaaaa");
|
|
msgOut.setFilenameLong((byte) 10);
|
|
msgOut.setFilenameVal("prueba.txt");
|
|
msgOut.writeMessageToOutputStream(dos);
|
|
System.out.println("sent " + PeerMessageOps.opcodeToOperation(msgOut.getOpcode()));
|
|
}
|
|
} catch (IOException e) {
|
|
// ???????
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Método que ejecuta el hilo principal del servidor en segundo plano, esperando
|
|
* conexiones de clientes.
|
|
*
|
|
* @see java.lang.Runnable#run()
|
|
*/
|
|
public void run() {
|
|
boolean stopServer = false; // HAY QUE CAMBIAR ESTO PORQUE NO SÉ DE DÓNDE COJONES SALE (ver TODO l. 147)
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
while (!stopServer) {
|
|
Socket socket = null;
|
|
boolean connectionOk = false;
|
|
try {
|
|
socket = serverSocket.accept();
|
|
connectionOk = true;
|
|
} catch (IOException e) {
|
|
System.err.println("Connection refused");
|
|
}
|
|
|
|
if (connectionOk) {
|
|
NFServerThread serverThread = new NFServerThread(socket, state);
|
|
serverThread.start();
|
|
int connNum = state.getNumberOfConnections();
|
|
InetSocketAddress clientAddr = (InetSocketAddress) socket.getRemoteSocketAddress();
|
|
System.out.println("New connection from " + clientAddr);
|
|
System.out.println("Total connections = " + connNum);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
InetSocketAddress clientAddr = (InetSocketAddress) socket.getRemoteSocketAddress();
|
|
try {
|
|
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
|
|
DataInputStream dis = new DataInputStream(socket.getInputStream());
|
|
while(true) {
|
|
|
|
PeerMessage msgIn = PeerMessage.readMessageFromInputStream(dis);
|
|
switch (msgIn.getOpcode()) {
|
|
case PeerMessageOps.OPCODE_REQUEST_PEER_FILES:
|
|
|
|
|
|
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];
|
|
|
|
msgOut.setFileHash(archivo.fileHash);
|
|
msgOut.setFileSize(archivo.fileSize);
|
|
msgOut.setFilenameVal(archivo.filePath + archivo.fileName);
|
|
msgOut.setFilenameLong((byte)archivo.fileName.length());
|
|
msgOut.setLast(false);
|
|
if (i == archivos.length - 1) msgOut.setLast(true);
|
|
msgOut.writeMessageToOutputStream(dos);
|
|
}
|
|
}
|
|
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|