/** * Clase MulticastServer.java *@author Diego del Valle *@author Diego Gonzalez */ import java.io.*; import java.net.*; import java.util.*; /**Clase que implementa cliente multicast que recepcionara informacion enviada por * *servidor multicast, con el objetivo de dibujar en pantalla una figura rebotando * *por las pantallas de los clientes * */ public class MulticastServer { private static final String MCAST_ADDR = "230.0.0.1"; private static final int MCAST_PORT = 9013; private static final int DGRAM_BUF_LEN = 512; private static final String DEFAULT_ARQUITECTURA = "rectangular"; private static final boolean DEFAULT_CIRCULAR = false; private static final int DEFAULT_WIDTH = 640; private static final int DEFAULT_HEIGTH = 480; private static final int DEFAULT_SERVIDORES = 1; private static final int MIN_WIDTH = 100 ; private static final int MAX_WIDTH = 1500; private static final int MIN_HEIGTH = 100; private static final int MAX_HEIGTH = 768; private static final int MIN_SERVIDORES = 1; private static final int MAX_SERVIDORES = 10; /**Metodo que muestra forma de usar la aplicacion *@param arquitectura valor por defecto de esta variable *@param circular valor por defecto de esta variable *@param width valor por defecto de esta variable *@param heigth valor por defecto de esta variable *@param servidores valor por defecto de esta variable */ public static void showUsage(String arquitectura, boolean circular, int width, int heigth, int servidores) { System.out.println("Usage: MulticastServer Modo_arquitectura Modo_circular Ancho_cliente Alto_cliente Numero_de_servidores"); System.out.println("Modo_arquitectura: rectangular o lineal"); System.out.println("Modo_circular: true o false"); System.out.println("Ancho_cliente: Ancho tamano ventana clientes, mayor o igual que " + MAX_WIDTH +", menor o igual que " + MIN_WIDTH); System.out.println("Alto_cliente: Alto tamano ventana clientes, mayor o igual que " + MAX_HEIGTH + ", menor o igual que " + MIN_HEIGTH); System.out.println("Numero_de_servidores: Numero de servidores que se conectaran, mayor que " + MIN_SERVIDORES + ", menor que " + MAX_SERVIDORES); System.out.println("Sin argumentos valores por defecto: MulticastServer " + arquitectura + " " + circular + " " + width + " " + heigth + " " + servidores); System.exit(1); } /**Metodo que muestra forma de usar la aplicacion *@param arquitectura valor por defecto de esta variable *@param circular valor por defecto de esta variable *@param width valor por defecto de esta variable *@param heigth valor por defecto de esta variable *@param servidores valor por defecto de esta variable *@param arg representa la arquitectura ingresada por el usuario *@return retorna verdadero o falso si arg esta dentro de las *arquitecturas implementadas */ public static boolean compareArquitectura(String arquitectura, boolean circular, int width, int heigth, int servidores, String arg) { if (arg.equals("rectangular") || arg.equals("lineal")) return true; showUsage(arquitectura, circular, width, heigth, servidores); return false; } /**Metodo que muestra forma de usar la aplicacion *@param arquitectura valor por defecto de esta variable *@param circular valor por defecto de esta variable *@param width valor por defecto de esta variable *@param heigth valor por defecto de esta variable *@param servidores valor por defecto de esta variable *@param arg representa si la arquitectura es circular o no ingresada *por el usuario *@return retorna verdadero si arg es true o false, false en cualquier *otro caso */ public static boolean compareCircular(String arquitectura, boolean circular, int width, int heigth, int servidores, String arg) { if (arg.equals("true") || arg.equals("false")) return true; showUsage(arquitectura, circular, width, heigth, servidores); return false; } /**Metodo que muestra forma de usar la aplicacion *@param arquitectura valor por defecto de esta variable *@param circular valor por defecto de esta variable *@param width valor por defecto de esta variable *@param heigth valor por defecto de esta variable *@param servidores valor por defecto de esta variable *@param arg representa si el ancho de la ventana para el cliente, esta *dentro de los limites o no *@return retorna verdadero si esta dentro de los limites */ public static boolean compareWidth(String arquitectura, boolean circular, int width, int heigth, int servidores, String arg) { try{ if (Integer.parseInt(arg) >= MIN_WIDTH && Integer.parseInt(arg) <= MAX_WIDTH) return true; showUsage(arquitectura, circular, width, heigth, servidores); } catch(NumberFormatException e) { e.printStackTrace(); showUsage(arquitectura, circular, width, heigth, servidores); return false; } return false; } /**Metodo que muestra forma de usar la aplicacion *@param arquitectura valor por defecto de esta variable *@param circular valor por defecto de esta variable *@param width valor por defecto de esta variable *@param heigth valor por defecto de esta variable *@param servidores valor por defecto de esta variable *@param arg representa si el alto de la ventana para el cliente, esta *dentro de los limites o no *@return retorna verdadero si esta dentro de los limites */ public static boolean compareHeigth(String arquitectura, boolean circular, int width, int heigth, int servidores, String arg) { try{ if (Integer.parseInt(arg) >= MIN_HEIGTH && Integer.parseInt(arg) <= MAX_HEIGTH) return true; showUsage(arquitectura, circular, width, heigth, servidores); } catch(NumberFormatException e) { e.printStackTrace(); showUsage(arquitectura, circular, width, heigth, servidores); return false; } return false; } /**Metodo que muestra forma de usar la aplicacion *@param arquitectura valor por defecto de esta variable *@param circular valor por defecto de esta variable *@param width valor por defecto de esta variable *@param heigth valor por defecto de esta variable *@param servidores valor por defecto de esta variable *@param arg representa si el numero de servidores esta *dentro de los limites o no *@return retorna verdadero si esta dentro de los limites */ public static boolean compareServidores(String arquitectura, boolean circular, int width, int heigth, int servidores, String arg) { try{ if (Integer.parseInt(arg) >= MIN_SERVIDORES && Integer.parseInt(arg) <= MAX_SERVIDORES) return true; showUsage(arquitectura, circular, width, heigth, servidores); } catch(NumberFormatException e) { e.printStackTrace(); showUsage(arquitectura, circular, width, heigth, servidores); return false; } return false; } /**Unico metodo de la clase que implementa a servidor aceptando conexion y enviando * datos a clientes */ public static void main(String[] args){ InetAddress group = null; int client_number = 4; int i = 0; String arquitectura = DEFAULT_ARQUITECTURA; boolean circular = DEFAULT_CIRCULAR; int width = DEFAULT_WIDTH; int heigth = DEFAULT_HEIGTH; int servidores = DEFAULT_SERVIDORES; String msg = "Welcome"; if (args.length != 0 && args.length != 5) { showUsage(arquitectura, circular, width, heigth, servidores); } else if(args.length == 5) { if (compareArquitectura(arquitectura, circular, width, heigth, servidores,args[0])) arquitectura = args[0]; if (compareCircular(arquitectura, circular, width, heigth, servidores,args[1])) circular = Boolean.parseBoolean(args[1]); if (compareWidth(arquitectura, circular, width, heigth, servidores,args[2])) width = Integer.parseInt(args[2]); if (compareHeigth(arquitectura, circular, width, heigth, servidores,args[3])) heigth = Integer.parseInt(args[3]); if (compareServidores(arquitectura, circular, width, heigth, servidores,args[4])) servidores = Integer.parseInt(args[4]); System.out.println("Server running with: MulticastServer " + args[0] + " "+ args[1] +" "+ args[2] +" "+ args[3] +" "+ args[4]); } try { group = InetAddress.getByName(MCAST_ADDR); } catch(UnknownHostException e) { e.printStackTrace(); System.exit(1); } MulticastSocket socket = null; try { socket = new MulticastSocket(MCAST_PORT); socket.joinGroup(group); } catch (IOException e) { e.printStackTrace(); System.exit(3); } ArrayList circulos = new ArrayList();; int threadCounter = 0; int server = servidores; while (servidores > 0) { Coordenadas coor = new Coordenadas(width, heigth, arquitectura, circular); circulos.add(coor); new ThreadedSendingDataHandler(group, MCAST_PORT, socket, width, heigth, arquitectura, circular, threadCounter, coor).start(); System.out.println("Starting ThreadServer :" + threadCounter); threadCounter++; servidores--; } ThreadedModifyingDataHandler dh = new ThreadedModifyingDataHandler(group, MCAST_PORT, socket, width, heigth, arquitectura, circular, circulos, server); System.out.println("Starting DataHandler server..."); dh.start(); } } /**Clase interna que implementa hebra para enviar datos a clientes */ class ThreadedSendingDataHandler extends Thread { /**Metodo constructor de manejador de clase interna para enviar datos a clientes *@param group informacion de grupo multicast *@param port puerto en el cual se recepcionan y envian datos *@param socket Conexion donde se recepcionan y envian datos *@param width tamano maximo de ancho de ventanas por cliente *@param heigth tamano maximo de alto de ventanas por cliente *@param arquitectura informa de la arquitectura del sistema *@param circular especifica si la arquitectura es circular o no *@param threadCounter Identificador del servidor *@param Objeto que contiene referencia a mapa del servidor y otros datos */ public ThreadedSendingDataHandler(InetAddress group, int port, MulticastSocket socket, int width, int heigth, String arquitectura, boolean circular, int threadCounter, Coordenadas coor) { int client_number = 0; group_mcast = group; port_mcast = port; socket_mcast = socket; baloon = coor; serverIdentifier = threadCounter; } /**Metodo run de ThreadedSendingDataHandler */ public void run() { System.out.println("...Server " + serverIdentifier + " Sending Data to clients..."); while (true) { try { byte[] buf = new byte[DGRAM_BUF_LEN]; DatagramPacket packet = new DatagramPacket(buf, buf.length); String info = Integer.toString(baloon.getWidth()) + " " + Integer.toString(baloon.getHeigth()) + " " + serverIdentifier + " "; buf = info.getBytes(); packet = new DatagramPacket(buf, buf.length, group_mcast, port_mcast); socket_mcast.send(packet); baloon.changeCoordinates(); } catch(IOException e) { e.printStackTrace(); } try{ sleep(ALARMA); } catch(InterruptedException e) { e.printStackTrace(); } } } //variables privadas private InetAddress group_mcast; private int port_mcast; private MulticastSocket socket_mcast; public static final long ALARMA = 1; public static final int DGRAM_BUF_LEN = 512; private Coordenadas baloon; private int serverIdentifier; } /**Clase interna que implementa hebra para recibir conexiones de clientes y administrar *modificaciones del mapa del sistema en base a eso */ class ThreadedModifyingDataHandler extends Thread { /**Metodo constructor de manejador de clase interna para enviar datos a clientes *@param group informacion de grupo multicast *@param port puerto en el cual se recepcionan y envian datos *@param socket Conexion donde se recepcionan y envian datos *@param width tamano maximo de ancho de ventanas por cliente *@param heigth tamano maximo de alto de ventanas por cliente *@param arquitectura especifica la arquitectura del sistema *@param circular especifica si arquitectura es circular o no *@param circulos especifica arreglo de Objetos Coordenadas(uno por cada servidor) */ public ThreadedModifyingDataHandler(InetAddress group, int port, MulticastSocket socket, int width, int heigth, String arquitectura, boolean circular, ArrayList circulos, int server) { int client_number = 0; group_mcast = group; port_mcast = port; socket_mcast = socket; this.circulos = circulos; this.width = width; this.heigth = heigth; this.arquitectura = arquitectura; this.circular = circular; this.server = server; client = new ArrayList(); } /**Metodo run de ThreadedModifyingDataHandler */ public void run() { System.out.println("...running server DataHandler..."); int clientNumber = 4; int clientCounter = 0; String msg = "Welcome"; while (true) { try { byte[] buf = new byte[DGRAM_BUF_LEN]; DatagramPacket packet = new DatagramPacket(buf, buf.length); socket_mcast.receive(packet); String result[] = new String(buf).split("\\s"); if (result[0].equals("Hello")) { System.out.println("Client " + result[0] + " requesting connection"); InetAddress clientAddr = packet.getAddress(); int port = packet.getPort(); client.add(new ClientData(clientAddr, port, width, heigth, circular, arquitectura, clientCounter)); clientCounter++; System.out.println("New client connection accepted...Modifying server configuration..."); for (int i = 0; i < client.size(); i++) { ClientData cl = ((ClientData)client.get(i)); cl.setData(clientCounter); String aux = msg + " " + i +" " + (client.size() - 1) + " " + cl.getWidth() + " " + cl.getHeigth() + " " + cl.getMinWidth() + " " + cl.getMinHeigth() + " " + cl.getUp() + " " + cl.getDown() + " " + cl.getLeft() + " " + cl.getRigth() + " " + server + " "; System.out.println("Sending configuration data to client " + i); buf = aux.getBytes(); packet = new DatagramPacket(buf, buf.length, group_mcast, port_mcast); System.out.println("Configuration Data: " + aux ); socket_mcast.send(packet); } for (int i = 0; i < circulos.size(); i++) { ((Coordenadas)circulos.get(i)).modify(clientCounter); } } } catch(IOException e) { e.printStackTrace(); } } } private InetAddress group_mcast; private int port_mcast; private MulticastSocket socket_mcast; public static final long ALARMA = 10; public static final int DGRAM_BUF_LEN = 512; private Coordenadas baloon; private int width; private int heigth; private String arquitectura; private ArrayList circulos; private ArrayList client; private boolean circular; private int server; }