Page 1
INSTITUTO TECNOLOGICO SUPERIOR DE
COATZACOALCOS
DIVICION: ING INFORMATICA
ASIGNATURA: PROGRAMACION CLIENTE SERVIDOR
DOCENTE: I.S.C LIZBETH HERNANDEZ OLAN
INTEGRANTES:
AVEDAÑO LOPEZ CARLOSCRUZ FERNANDEZ ALBERTO
IZQUIERDO CRUZ PATRICIA DEL CARMENMARTINEZ ANTONIO IRIDIAN
PEREZ HERNANDEZ MISAEL DE JESUSREYES GARCIA ALAN
TEMA:
AVANCES DE PROYECTO 4
GRADO: 7 GRUPO: B
COATZACOALCOS, VER A 9 DE DICIEMBRE DEL 2015
Page 2
// Fig. 24.15: ClienteTresEnRaya.java
// Cliente que permite a un usuario jugar Tres en raya con otro a través de una red.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.Socket;
import java.net.InetAddress;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.util.Formatter;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class ClienteTresEnRaya extends JFrame implements Runnable
{
private JTextField campoId; // campo de texto para mostrar la marca del jugador
private JTextArea areaPantalla; // objeto JTextArea para mostrar la salida
private JPanel panelTablero; // panel para el tablero de tres en raya
private JPanel panel2; // panel que contiene el tablero
private Cuadro tablero[][]; // tablero de tres en raya
private Cuadro cuadroActual; // el cuadro actual
private Socket conexion; // conexión con el servidor
Page 3
private Scanner entrada; // entrada del servidor
private Formatter salida; // salida al servidor
private String hostTresEnRaya; // nombre de host para el servidor
private String miMarca; // la marca de este cliente
private boolean miTurno; // determina de qué cliente es el turno
private final String MARCA_X = "X"; // marca para el primer cliente
private final String MARCA_O = "O"; // marca para el segundo cliente
// establece la interfaz de usuario y el tablero
public ClienteTresEnRaya( String host )
{
hostTresEnRaya = host; // establece el nombre del servidor
areaPantalla = new JTextArea( 4, 30 ); // establece objeto JTextArea
areaPantalla.setEditable( false );
add( new JScrollPane( areaPantalla ), BorderLayout.SOUTH );
panelTablero = new JPanel(); // establece panel para los cuadros en el tablero
panelTablero.setLayout( new GridLayout( 3, 3, 0, 0 ) );
tablero = new Cuadro[ 3 ][ 3 ]; // crea el tablero
// itera a través de las filas en el tablero
for ( int fila = 0; fila < tablero.length; fila++ )
{
// itera a través de las columnas en el tablero
for ( int columna = 0; columna < tablero[ fila ].length; columna++ )
{
// crea un cuadro
tablero[ fila ][ columna ] = new Cuadro( "",fila * 3 + columna );
panelTablero.add( tablero[ fila ][ columna ] ); // agrega el cuadro
} // fin de for interior
} // fin de for exterior
campoId = new JTextField(); // establece campo de texto
campoId.setEditable( false );
Page 4
add( campoId, BorderLayout.NORTH );
panel2 = new JPanel(); // establece el panel que contiene a panelTablero
panel2.add( panelTablero, BorderLayout.CENTER ); // agrega el panel deltablero
add( panel2, BorderLayout.CENTER ); // agrega el panel contenedor
setSize( 325, 225 ); // establece el tamaño de la ventana
setVisible( true ); // muestra la ventana
iniciarCliente();
} // fin del constructor de ClienteTresEnRaya
// inicia el subproceso cliente
public void iniciarCliente()
{
try // se conecta al servidor, obtiene los flujos e inicia subproceso de salida
{
// realiza conexión con el servidor
conexion = new Socket(
InetAddress.getByName( hostTresEnRaya ), 12345 );
// obtiene flujos para entrada y salida
entrada = new Scanner( conexion.getInputStream() );
salida = new Formatter( conexion.getOutputStream() );
} // fin de try
catch ( IOException excepcionES )
{
excepcionES.printStackTrace();
} // fin de catch
// crea e inicia subproceso trabajador para este cliente
ExecutorService trabajador = Executors.newFixedThreadPool( 1 );
trabajador.execute( this ); // ejecuta el cliente
} // fin del método iniciarCliente
// subproceso de control que permite la actualización continua de areaPantalla
public void run()
Page 5
{
miMarca = entrada.nextLine(); // obtiene la marca del jugador (X o O)
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
// muestra la marca del jugador
campoId.setText( "Usted es el jugador \"" + miMarca + "\"" );
} // fin del método run
} // fin de la clase interna anónima
); // fin de la llamada a SwingUtilities.invokeLater
miTurno = ( miMarca.equals( MARCA_X ) ); // determina si es turno del cliente
// recibe los mensajes que se envían al cliente y los imprime en pantalla
while ( true )
{
if ( entrada.hasNextLine() )
procesarMensaje( entrada.nextLine() );
} // fin de while
} // fin del método run
// procesa los mensajes recibidos por el cliente
private void procesarMensaje( String mensaje )
{
// ocurrió un movimiento válido
if ( mensaje.equals( "Movimiento valido." ) )
{
mostrarMensaje( "Movimiento valido, por favor espere.\n" );
establecerMarca( cuadroActual, miMarca ); // establece marca en el cuadro
} // fin de if
else if ( mensaje.equals( "Movimiento invalido, intente de nuevo" ) )
Page 6
{
mostrarMensaje( mensaje + "\n" ); // muestra el movimiento inválido
miTurno = true; // sigue siendo turno de este cliente
} // fin de else if
else if ( mensaje.equals( "El oponente realizo movimiento" ) )
{
int ubicacion = entrada.nextInt(); // obtiene la ubicación del movimiento
entrada.nextLine(); // salta nueva línea después de la ubicación int
int fila = ubicacion / 3; // calcula la fila
int columna = ubicacion % 3; // calcula la columna
establecerMarca( tablero[ fila ][ columna ],
( miMarca.equals( MARCA_X ) ? MARCA_O : MARCA_X ) ); // marca el movimiento
mostrarMensaje( "El oponente hizo un movimiento. Ahora es su turno.\n" );
miTurno = true; // ahora es turno de este cliente
} // fin de else if
else
mostrarMensaje( mensaje + "\n" ); // muestra el mensaje
} // fin del método procesarMensaje
// manipula el objeto areaSalida en el subproceso despachador de eventos
private void mostrarMensaje( final String mensajeAMostrar )
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
areaPantalla.append( mensajeAMostrar ); // actualiza la salida
} // fin del método run
} // fin de la clase interna
); // fin de la llamada a SwingUtilities.invokeLater
Page 7
} // fin del método mostrarMensaje
// método utilitario para establecer una marca en el tablero, en el subprocesodespachador de eventos
private void establecerMarca( final Cuadro cuadroAMarcar, final String marca )
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
cuadroAMarcar.establecerMarca( marca ); // establece la marca en elcuadro
} // fin del método run
} // fin de la clase interna anónima
); // fin de la llamada a SwingUtilities.invokeLater
} // fin del método establecerMarca
// envía un mensaje al servidor, indicando el cuadro en el que se hizo clic
public void enviarCuadroClic( int ubicacion )
{
// si es mi turno
if ( miTurno )
{
salida.format( "%d\n", ubicacion ); // envía la ubicación al servidor
salida.flush();
miTurno = false; // ya no es mi turno
} // fin de if
} // fin del método enviarCuadroClic
// establece el cuadro actual
public void establecerCuadroActual( Cuadro cuadro )
{
cuadroActual = cuadro; // asigna el argumento al cuadro actual
Page 8
} // fin del método establecerCuadroActual
// clase interna privada para los cuadros en el tablero
private class Cuadro extends JPanel
{
private String marca; // marca a dibujar en este cuadro
private int ubicacion; // ubicacion del cuadro
public Cuadro( String marcaCuadro, int ubicacionCuadro )
{
marca = marcaCuadro; // establece la marca para este cuadro
ubicacion = ubicacionCuadro; // establece la ubicación de este cuadro
addMouseListener(
new MouseAdapter()
{
public void mouseReleased( MouseEvent e )
{
establecerCuadroActual( Cuadro.this ); // establece el cuadro actual
// envía la ubicación de este cuadro
enviarCuadroClic( obtenerUbicacionCuadro() );
} // fin del método mouseReleased
} // fin de la clase interna anónima
); // fin de la llamada a addMouseListener
} // fin del constructor de Cuadro
// devuelve el tamaño preferido del objeto Cuadro
public Dimension getPreferredSize()
{
return new Dimension( 30, 30 ); // devuelve el tamaño preferido
} // fin del método getPreferredSize
// devuelve el tamaño mínimo del objeto Cuadro
public Dimension getMinimumSize()
{
Page 9
return getPreferredSize(); // devuelve el tamaño preferido
} // fin del método getMinimumSize
// establece la marca para el objeto Cuadro
public void establecerMarca( String nuevaMarca )
{
marca = nuevaMarca; // establece la marca del cuadro
repaint(); // vuelve a pintar el cuadro
} // fin del método establecerMarca
// devuelve la ubicación del objeto Cuadro
public int obtenerUbicacionCuadro()
{
return ubicacion; // devuelve la ubicación del cuadro
} // fin del método obtenerUbicacionCuadro
// dibuja el objeto Cuadro
public void paintComponent( Graphics g )
{
super.paintComponent( g );
g.drawRect( 0, 0, 29, 29 ); // dibuja el cuadro
g.drawString( marca, 11, 20 ); // dibuja la marca
} // fin del método paintComponent
} // fin de la clase interna Cuadro
} // fin de la clase ClienteTresEnRaya
Page 10
// Fig. 24.16: PruebaClienteTresEnRaya.java
// Prueba la clase ClienteTresEnRaya.
import javax.swing.JFrame;
public class PruebaClienteTresEnRaya
{
public static void main( String args[] )
{
ClienteTresEnRaya aplicacion; // declara la aplicación cliente
// si no hay argumentos de línea de comandos
if ( args.length == 0 )
aplicacion = new ClienteTresEnRaya( "127.0.0.1" ); // localhost
else
aplicacion = new ClienteTresEnRaya( args[ 0 ] ); // usa args
aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
} // fin de main
} // fin de la clase PruebaClienteTresEnRaya
Page 11
// Fig. 24.16: PruebaClienteTresEnRaya.java
// Prueba la clase ClienteTresEnRaya.
import javax.swing.JFrame;
public class PruebaClienteTresEnRaya
{
public static void main( String args[] )
{
ClienteTresEnRaya aplicacion; // declara la aplicación cliente
// si no hay argumentos de línea de comandos
if ( args.length == 0 )
aplicacion = new ClienteTresEnRaya( "127.0.0.1" ); // localhost
else
aplicacion = new ClienteTresEnRaya( args[ 0 ] ); // usa args
aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
} // fin de main
} // fin de la clase PruebaClienteTresEnRaya
Page 12
// Fig. 24.13: ServidorTresEnRaya.java
// Esta clase mantiene un juego de Tres en raya para dos clientes.
import java.awt.BorderLayout;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.util.Formatter;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class ServidorTresEnRaya extends JFrame
{
private String[] tablero = new String[ 9 ]; // tablero de tres en raya
private JTextArea areaSalida; // para imprimir los movimientos en pantalla
private Jugador[] jugadores; // arreglo de objetos Jugador
private ServerSocket servidor; // socket servidor para conectarse con los clientes
private int jugadorActual; // lleva la cuenta del jugador que sigue en turno
private final static int JUGADOR_X = 0; // constante para el primer jugador
private final static int JUGADOR_O = 1; // constante para el segundo jugador
private final static String[] MARCAS = { "X", "O" }; // arreglo de marcas
private ExecutorService ejecutarJuego; // ejecuta a los jugadores
private Lock bloqueoJuego; // para bloquear el juego y estar sincronizado
private Condition otroJugadorConectado; // para esperar al otro jugador
private Condition turnoOtroJugador; // para esperar el turno del otro jugador
Page 13
// establece servidor de tres en raya y GUI para mostrar mensajes en pantalla
public ServidorTresEnRaya()
{
super( "Servidor de Tres en raya" ); // establece el título de la ventana
// crea objeto ExecutorService con un subproceso para cada jugador
ejecutarJuego = Executors.newFixedThreadPool( 2 );
bloqueoJuego = new ReentrantLock(); // crea bloqueo para el juego
// variable de condición para los dos jugadores conectados
otroJugadorConectado = bloqueoJuego.newCondition();
// variable de condición para el turno del otro jugador
turnoOtroJugador = bloqueoJuego.newCondition();
for ( int i = 0; i < 9; i++ )
tablero[ i ] = new String( "" ); // crea tablero de tres en raya
jugadores = new Jugador[ 2 ]; // crea arreglo de jugadores
jugadorActual = JUGADOR_X; // establece el primer jugador como el jugador actual
try
{
servidor = new ServerSocket( 12345, 2 ); // establece objeto ServerSocket
} // fin de try
catch ( IOException excepcionES )
{
excepcionES.printStackTrace();
System.exit( 1 );
} // fin de catch
areaSalida = new JTextArea(); // crea objeto JTextArea para mostrar la salida
add( areaSalida, BorderLayout.CENTER );
areaSalida.setText( "Servidor esperando conexiones\n" );
setSize( 300, 300 ); // establece el tamaño de la ventana
setVisible( true ); // muestra la ventana
Page 14
} // fin del constructor de ServidorTresEnRaya
// espera dos conexiones para poder jugar
public void execute()
{
// espera a que se conecte cada cliente
for ( int i = 0; i < jugadores.length; i++ )
{
try // espera la conexión, crea el objeto Jugador, inicia objeto Runnable
{
jugadores[ i ] = new Jugador( servidor.accept(), i );
ejecutarJuego.execute( jugadores[ i ] ); // ejecuta el objeto Runnable jugador
} // fin de try
catch ( IOException excepcionES )
{
excepcionES.printStackTrace();
System.exit( 1 );
} // fin de catch
} // fin de for
bloqueoJuego.lock(); // bloquea el juego para avisar al subproceso del jugador X
try
{
jugadores[ JUGADOR_X ].establecerSuspendido( false ); // continúa el jugador X
otroJugadorConectado.signal(); // despierta el subproceso del jugador X
} // fin de try
finally
{
bloqueoJuego.unlock(); // desbloquea el juego después de avisar al jugador X
} // fin de finally
} // fin del método execute
Page 15
// muestra un mensaje en objeto areaSalida
private void mostrarMensaje( final String mensajeAMostrar )
{
// muestra un mensaje del subproceso de ejecución despachador de eventos
SwingUtilities.invokeLater(
new Runnable()
{
public void run() // actualiza el objeto areaSalida
{
areaSalida.append( mensajeAMostrar ); // agrega el mensaje
} // fin del método run
} // fin de la clase interna
); // fin de la llamada a SwingUtilities.invokeLater
} // fin del método mostrarMensaje
// determina si el movimiento es válido
public boolean validarYMover( int ubicacion, int jugador )
{
// mientras no sea el jugador actual, debe esperar su turno
while ( jugador != jugadorActual )
{
bloqueoJuego.lock(); // bloquea el juego para esperar a que el otro jugadorhaga su movmiento
try
{
turnoOtroJugador.await(); // espera el turno de jugador
} // fin de try
catch ( InterruptedException excepcion )
{
excepcion.printStackTrace();
} // fin de catch
Page 16
finally
{
bloqueoJuego.unlock(); // desbloquea el juego después de esperar
} // fin de finally
} // fin de while
// si la ubicación no está ocupada, realiza el movimiento
if ( !estaOcupada( ubicacion ) )
{
tablero[ ubicacion ] = MARCAS[ jugadorActual ]; // establece el movimiento en el tablero
jugadorActual = ( jugadorActual + 1 ) % 2; // cambia el jugador
// deja que el nuevo jugador sepa que se realizó un movimiento
jugadores[ jugadorActual ].otroJugadorMovio( ubicacion );
bloqueoJuego.lock(); // bloquea el juego para indicar al otro jugador querealice su movimiento
try
{
turnoOtroJugador.signal(); // indica al otro jugador que debe continuar
} // fin de try
finally
{
bloqueoJuego.unlock(); // desbloquea el juego despues de avisar
} // fin de finally
return true; // notifica al jugador que el movimiento fue válido
} // fin de if
else // el movimiento no fue válido
return false; // notifica al jugador que el movimiento fue inválido
} // fin del método validarYMover
// determina si la ubicación está ocupada
Page 17
public boolean estaOcupada( int ubicacion )
{
if ( tablero[ ubicacion ].equals( MARCAS[ JUGADOR_X ] ) ||
tablero [ ubicacion ].equals( MARCAS[ JUGADOR_O ] ) )
return true; // la ubicación está ocupada
else
return false; // la ubicación no está ocupada
} // fin del método estaOcupada
// coloca código en este método para determinar si terminó el juego
public boolean seTerminoJuego()
{
return false; // esto se deja como ejercicio
} // fin del método seTerminoJuego
// la clase interna privada Jugador maneja a cada Jugador como objeto Runnable
private class Jugador implements Runnable
{
private Socket conexion; // conexión con el cliente
private Scanner entrada; // entrada del cliente
private Formatter salida; // salida al cliente
private int numeroJugador; // rastrea cuál jugador es el actual
private String marca; // marca para este jugador
private boolean suspendido = true; // indica si el subproceso está suspendido
// establece el subproceso Jugador
public Jugador( Socket socket, int numero )
{
numeroJugador = numero; // almacena el número de este jugador
marca = MARCAS[ numeroJugador ]; // especifica la marca del jugador
conexion = socket; // almacena socket para el cliente
try // obtiene los flujos del objeto Socket
{
Page 18
entrada = new Scanner( conexion.getInputStream() );
salida = new Formatter( conexion.getOutputStream() );
} // fin de try
catch ( IOException excepcionES )
{
excepcionES.printStackTrace();
System.exit( 1 );
} // fin de catch
} // fin del constructor de Jugador
// envía mensaje que indica que el otro jugador hizo un movimiento
public void otroJugadorMovio( int ubicacion )
{
salida.format( "El oponente realizo movimiento\n" );
salida.format( "%d\n", ubicacion ); // envía la ubicación del movimiento
salida.flush(); // vacía la salida
} // fin del método otroJugadorMovio
// controla la ejecución del subproceso
public void run()
{
// envía al cliente su marca (X o O), procesa los mensajes del cliente
try
{
mostrarMensaje( "Jugador " + marca + " conectado\n" );
salida.format( "%s\n", marca ); // envía la marca del jugador
salida.flush(); // vacía la salida
// si es el jugador X, espera a que llegue el otro jugador
if ( numeroJugador == JUGADOR_X )
{
salida.format( "%s\n%s", "Jugador X conectado",
Page 19
"Esperando al otro jugador\n" );
salida.flush(); // vacía la salida
bloqueoJuego.lock(); // bloquea el juego para esperar al segundo jugador
try
{
while( suspendido )
{
otroJugadorConectado.await(); // espera al jugador O
} // fin de while
} // fin de try
catch ( InterruptedException excepcion )
{
excepcion.printStackTrace();
} // fin de catch
finally
{
bloqueoJuego.unlock(); // desbloquea el juego después del segundojugador
} // fin de finally
// envía un mensaje que indica que el otro jugador se conectó
salida.format( "El otro jugador se conecto. Ahora es su turno.\n" );
salida.flush(); // vacía la salida
} // fin de if
else
{
salida.format( "El jugador O se conecto, por favor espere\n" );
salida.flush(); // vacía la salida
} // fin de else
// mientras el juego no termine
while ( !seTerminoJuego() )
{
Page 20
int ubicacion = 0; // inicializa la ubicación del movimiento
if ( entrada.hasNext() )
ubicacion = entrada.nextInt(); // obtiene la ubicación del movimiento
// comprueba si el movimiento es válido
if ( validarYMover( ubicacion, numeroJugador ) )
{
mostrarMensaje( "\nubicacion: " + ubicacion );
salida.format( "Movimiento valido.\n" ); // notifica al cliente
salida.flush(); // vacía la salida
} // fin de if
else // el movimiento fue inválido
{
salida.format( "Movimiento invalido, intente de nuevo\n" );
salida.flush(); // vacía la salida
} // fin de else
} // fin de while
} // fin de try
finally
{
try
{
conexion.close(); // cierra la conexión con el cliente
} // fin de try
catch ( IOException excepcionES )
{
excepcionES.printStackTrace();
System.exit( 1 );
} // fin de catch
} // fin de finally
} // fin del método run
Page 21
// establece si se suspende el subproceso o no
public void establecerSuspendido( boolean estado )
{
suspendido = estado; // establece el valor de suspendido
} // fin del método establecerSuspendido
} // fin de la clase Jugador
} // fin de la clase ServidorTresEnRaya