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.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(); } } }