/*

Direccion IP
Es 4 pares de numeros, que representan a un nodo (host) unico en la
red

Puerto TCP
Es un numero que adquiere un programa que se declara como servidor
y a este puerto se ata, escuchando peticiones.


Socket:

Es un mecanismo de programación para que dos programas, un cliente
y un servidor se comuniquen.


Un socket es una tuberia virtual que se establece entre dos
programas y por el cual fluyen bytes.


En java se implanta utilizando el paquete java.net
Para codificar a un servidor,se utiliza a la clase ServerSocket,
que es un objeto que permite ligarse con el puerto servidor.
Un servidor se queda en espera de conexiones (en estado de accept)
y por cada conexion establecida, el sevidor manipula a un objeto
de tipo Socket.
La clase Socket permite obtener flujos de tipo OutputStream e InputStream

Del lado cliente, en Java se tiene que crear un objeto de tipo Socket, que se
instancia a partir de una direcciób IP y puerto TCP de un servidor remoto
*/
import java.net.ServerSocket;
import java.net.Socket;
import java.io.OutputStream;
import java.io.IOException;
import java.util.Arrays;
public class MiServidorHilos implements Runnable {
    public final static int CAPACIDAD=1024*1024;
    private int puerto;
    private boolean continuar=false;
    private ServerSocket elServidor;
    public MiServidorHilos(int elPuerto) { puerto=elPuerto;}
    public void setContinuar(boolean valor) { this.continuar=valor;}
    public void esperar() {
        System.out.println("Para finalizar, dar cualquier tecla");
        try { System.in.read();} catch (IOException ex) {}
        this.setContinuar(false);
        System.out.println("Fin de conexion");
    }
    public void servirHilo(Socket conexion) throws IOException { 
       System.out.println("Procesando a cliente "+conexion.getInetAddress());  
       OutputStream laSalida = conexion.getOutputStream();//obtener flujo escritura
       int dato = 65;
       byte [] arreglo = new byte[CAPACIDAD];
       Arrays.fill(arreglo,(byte)dato);
       int escritos = 0, offset=0;
       do {
          laSalida.write(arreglo,offset,1024);//escribir 1024 bytes
          laSalida.flush(); //vaciar el stream, para que se escriba al socket
          offset+=1024;
       } while (offset<CAPACIDAD );
       
       laSalida.close();
       conexion.close();
    }
    public void servir(Socket conexion) {
        Thread elHilo = new Thread(new HiloServidor(conexion));
        elHilo.start();
    }
    public void run() {
      this.continuar = true;
      try {   
        this.elServidor = new ServerSocket(puerto); //activar servidor
        while (this.continuar) { 
         Socket conexion=elServidor.accept(); //esperar por conexiones
         this.servir(conexion); //procesar socket
        }
        this.elServidor.close();
      } catch (IOException laExcepcion) {
           System.err.println("Error en servir "+laExcepcion.getMessage());
      }
    }
    public static void main(String [] args) {
       if (args.length > 0) {
          String sPuerto = args[0];
          System.out.println("Escuchando en puerto "+sPuerto);
          try {
             int elPuerto=Integer.parseInt(sPuerto);
             MiServidorHilos s = new MiServidorHilos(elPuerto);
             Thread th = new Thread(s);
             th.start();
             s.esperar();
          } catch (NumberFormatException laExcepcion) {
             System.err.println("Indicar correctamente puerto "+laExcepcion.getMessage());
          }
       } else { System.err.println("Indicar puerto TCP del servidor!!");}
    }

}