Sockets y Swing
Saludos a todos, tengo un problema con este programa (estaba modificando un ejemplo de internet a través de Netbeans) y no tengo idea porque no puedo ejecutar el Servidor, se queda colgado y ni siquiera aparece la ventana que puse para simular dicho servidor porque no quiero hacerlo desde cónsola. No entiendo que sucede, estoy comenzando a experimentar con el uso de socket, gracias por su ayuda.
package dominio;
import java.io.*;
import java.net.*;
import javax.swing.*;
public class Servidor {
private ObjectOutputStream salida;
private ObjectInputStream entrada;
private ServerSocket servidor;
private Socket conexion;
private int contador = 1;
private JTextArea areaPantalla;
public void mostrarMensaje( String mensajeAMostrar, JTextArea areaPantalla )
{
areaPantalla.append( mensajeAMostrar );
areaPantalla.setCaretPosition(areaPantalla.getText().length() );
}
public void enviarDatos( String mensaje,JTextArea areaPantalla )
{
// enviar objeto al cliente
try {
salida.writeObject( "SERVIDOR>>> " + mensaje );
salida.flush();
mostrarMensaje( "\nSERVIDOR>>> " + mensaje,areaPantalla );
}
// procesar problemas que pueden ocurrir al enviar el objeto
catch ( IOException excepcionES ) {
areaPantalla.append( "\nError al escribir objeto" );
}
}
public void esperarConexion(JTextArea areaPantalla) throws IOException
{
mostrarMensaje( "Esperando una conexión\n",areaPantalla );
conexion = servidor.accept(); // permitir al servidor aceptar la conexión
mostrarMensaje( "Conexión " + contador + " recibida de: " +
conexion.getInetAddress().getHostName(),areaPantalla );
}
// obtener flujos para enviar y recibir datos
public void obtenerFlujos() throws IOException
{
// establecer flujo de salida para los objetos
salida = new ObjectOutputStream( conexion.getOutputStream() );
salida.flush(); // vaciar bufer de salida para enviar información de encabezado
// establecer flujo de entrada para los objetos
entrada = new ObjectInputStream( conexion.getInputStream() );
mostrarMensaje( "\nSe recibieron los flujos de E/S\n",areaPantalla );
}
// procesar la conexión con el cliente
public void procesarConexion(JTextField campoMensajes) throws IOException
{
// enviar mensaje de conexión exitosa al cliente
String mensaje = "Conexión exitosa";
enviarDatos( mensaje,areaPantalla );
// habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes
campoMensajes.setEditable( true);
do { // procesar los mensajes enviados por el cliente
// leer el mensaje y mostrarlo en pantalla
try {
mensaje = ( String ) entrada.readObject();
mostrarMensaje( "\n" + mensaje,areaPantalla );
}
// atrapar problemas que pueden ocurrir al tratar de leer del cliente
catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {
mostrarMensaje( "\nSe recibió un tipo de objeto desconocido",areaPantalla );
}
} while ( !mensaje.equals( "CLIENTE>>> TERMINAR" ) );
} // fin del método procesarConexion
// cerrar flujos y socket
private void cerrarConexion(JTextField campoMensajes)
{
mostrarMensaje( "\nFinalizando la conexión\n",areaPantalla );
campoMensajes.setEditable( false ); // deshabilitar campoMensajes
try {
salida.close();
entrada.close();
conexion.close();
}
catch( IOException excepcionES ) {
System.err.println( "Error de Entrada Salida" );
}
}
public void ejecutarServidor(JTextField campoMensajes,JTextArea areaPantalla)
{
// configurar servidor para que reciba conexiones; procesar las conexiones
try {
// Paso 1: crear un objeto ServerSocket.
servidor = new ServerSocket( 12345, 100);
while ( true ) {
try {
esperarConexion(areaPantalla); // Paso 2: esperar una conexión.
obtenerFlujos(); // Paso 3: obtener flujos de entrada y salida.
procesarConexion(campoMensajes); // Paso 4: procesar la conexión.
}
// procesar excepción EOFException cuando el cliente cierre la conexión
catch ( EOFException excepcionEOF ) {
System.err.println( "El servidor terminó la conexión" );
}
finally {
cerrarConexion(campoMensajes); // Paso 5: cerrar la conexión.
++contador;
}
} // fin de instrucci�n while
} // fin del bloque try
// procesar problemas con E/S
catch ( IOException excepcionES ) {
System.err.println( "Error de Entrada Salida" );
}
} // fin del método ejecutarServidor
}
package gui;
import dominio.Servidor;
public class VentanaServidor extends javax.swing.JFrame {
Servidor aplicacion = new Servidor();
/** Creates new form VentanaServidor */
public VentanaServidor() {
initComponents();
campoMensajes.setEditable( false );
this.setLocationRelativeTo(null);
// this.setIconImage(new ImageIcon("src/imagenes/stuIconN.png").getImage());
this.setResizable(false);
campoMensajes.setText("");
aplicacion.ejecutarServidor(campoMensajes,areaPantalla);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
campoMensajes = new javax.swing.JTextField();
jScrollPane1 = new javax.swing.JScrollPane();
areaPantalla = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());
jPanel1.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());
campoMensajes.setText("jTextField1");
campoMensajes.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
campoMensajesActionPerformed(evt);
}
});
jPanel1.add(campoMensajes, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 20, 480, 40));
areaPantalla.setColumns(20);
areaPantalla.setRows(5);
jScrollPane1.setViewportView(areaPantalla);
jPanel1.add(jScrollPane1, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 70, 480, 250));
getContentPane().add(jPanel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 10, 520, 340));
pack();
}// </editor-fold>
private void campoMensajesActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
aplicacion.enviarDatos(campoMensajes.getText(), areaPantalla);
campoMensajes.setText("");
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new VentanaServidor().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JTextArea areaPantalla;
private javax.swing.JTextField campoMensajes;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration
}
<blockcode>
import java.io.*;
import java.net.*;
import javax.swing.*;
public class Servidor {
private ObjectOutputStream salida;
private ObjectInputStream entrada;
private ServerSocket servidor;
private Socket conexion;
private int contador = 1;
private JTextArea areaPantalla;
public void mostrarMensaje( String mensajeAMostrar, JTextArea areaPantalla )
{
areaPantalla.append( mensajeAMostrar );
areaPantalla.setCaretPosition(areaPantalla.getText().length() );
}
public void enviarDatos( String mensaje,JTextArea areaPantalla )
{
// enviar objeto al cliente
try {
salida.writeObject( "SERVIDOR>>> " + mensaje );
salida.flush();
mostrarMensaje( "\nSERVIDOR>>> " + mensaje,areaPantalla );
}
// procesar problemas que pueden ocurrir al enviar el objeto
catch ( IOException excepcionES ) {
areaPantalla.append( "\nError al escribir objeto" );
}
}
public void esperarConexion(JTextArea areaPantalla) throws IOException
{
mostrarMensaje( "Esperando una conexión\n",areaPantalla );
conexion = servidor.accept(); // permitir al servidor aceptar la conexión
mostrarMensaje( "Conexión " + contador + " recibida de: " +
conexion.getInetAddress().getHostName(),areaPantalla );
}
// obtener flujos para enviar y recibir datos
public void obtenerFlujos() throws IOException
{
// establecer flujo de salida para los objetos
salida = new ObjectOutputStream( conexion.getOutputStream() );
salida.flush(); // vaciar bufer de salida para enviar información de encabezado
// establecer flujo de entrada para los objetos
entrada = new ObjectInputStream( conexion.getInputStream() );
mostrarMensaje( "\nSe recibieron los flujos de E/S\n",areaPantalla );
}
// procesar la conexión con el cliente
public void procesarConexion(JTextField campoMensajes) throws IOException
{
// enviar mensaje de conexión exitosa al cliente
String mensaje = "Conexión exitosa";
enviarDatos( mensaje,areaPantalla );
// habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes
campoMensajes.setEditable( true);
do { // procesar los mensajes enviados por el cliente
// leer el mensaje y mostrarlo en pantalla
try {
mensaje = ( String ) entrada.readObject();
mostrarMensaje( "\n" + mensaje,areaPantalla );
}
// atrapar problemas que pueden ocurrir al tratar de leer del cliente
catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {
mostrarMensaje( "\nSe recibió un tipo de objeto desconocido",areaPantalla );
}
} while ( !mensaje.equals( "CLIENTE>>> TERMINAR" ) );
} // fin del método procesarConexion
// cerrar flujos y socket
private void cerrarConexion(JTextField campoMensajes)
{
mostrarMensaje( "\nFinalizando la conexión\n",areaPantalla );
campoMensajes.setEditable( false ); // deshabilitar campoMensajes
try {
salida.close();
entrada.close();
conexion.close();
}
catch( IOException excepcionES ) {
System.err.println( "Error de Entrada Salida" );
}
}
public void ejecutarServidor(JTextField campoMensajes,JTextArea areaPantalla)
{
// configurar servidor para que reciba conexiones; procesar las conexiones
try {
// Paso 1: crear un objeto ServerSocket.
servidor = new ServerSocket( 12345, 100);
while ( true ) {
try {
esperarConexion(areaPantalla); // Paso 2: esperar una conexión.
obtenerFlujos(); // Paso 3: obtener flujos de entrada y salida.
procesarConexion(campoMensajes); // Paso 4: procesar la conexión.
}
// procesar excepción EOFException cuando el cliente cierre la conexión
catch ( EOFException excepcionEOF ) {
System.err.println( "El servidor terminó la conexión" );
}
finally {
cerrarConexion(campoMensajes); // Paso 5: cerrar la conexión.
++contador;
}
} // fin de instrucci�n while
} // fin del bloque try
// procesar problemas con E/S
catch ( IOException excepcionES ) {
System.err.println( "Error de Entrada Salida" );
}
} // fin del método ejecutarServidor
}
package gui;
import dominio.Servidor;
public class VentanaServidor extends javax.swing.JFrame {
Servidor aplicacion = new Servidor();
/** Creates new form VentanaServidor */
public VentanaServidor() {
initComponents();
campoMensajes.setEditable( false );
this.setLocationRelativeTo(null);
// this.setIconImage(new ImageIcon("src/imagenes/stuIconN.png").getImage());
this.setResizable(false);
campoMensajes.setText("");
aplicacion.ejecutarServidor(campoMensajes,areaPantalla);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jPanel1 = new javax.swing.JPanel();
campoMensajes = new javax.swing.JTextField();
jScrollPane1 = new javax.swing.JScrollPane();
areaPantalla = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());
jPanel1.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());
campoMensajes.setText("jTextField1");
campoMensajes.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
campoMensajesActionPerformed(evt);
}
});
jPanel1.add(campoMensajes, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 20, 480, 40));
areaPantalla.setColumns(20);
areaPantalla.setRows(5);
jScrollPane1.setViewportView(areaPantalla);
jPanel1.add(jScrollPane1, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 70, 480, 250));
getContentPane().add(jPanel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 10, 520, 340));
pack();
}// </editor-fold>
private void campoMensajesActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
aplicacion.enviarDatos(campoMensajes.getText(), areaPantalla);
campoMensajes.setText("");
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new VentanaServidor().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JTextArea areaPantalla;
private javax.swing.JTextField campoMensajes;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration
}
<blockcode>
- Inicie sesión o regístrese para enviar comentarios
Ese tema hace largo tiempo
Ese tema hace largo tiempo no lo veo , pero puedes revisar el capitulo de Redes del libro "Como programar en Java " de Deitel(en español 5, 6, 7 edicion), en el que precisamente abordan un ejemplo muy completo de chat Cliente-Servidor, con interfaz gráfica incluida.
Espero te sirva.
vi el chat pero..
Hola, gracias por responder, yo revisé el ejemplo de Deitel y funciona. Lo único distinto con relación a este programa es que la interfaz se construye desde Netbeans y no vía código, por eso no entiendo porque no funciona si en esencia es casi lo mismo. Al ejecutar el Servidor debería aparecer la ventana con el mensaje Esperando Conexión y no lo hace se queda colgado...
Cuando creas una aplicacion
Cuando creas una aplicacion con java, esta es monotarea, es decir puede hacer solo una tarea a la vez, el ejemplo que pusiste se congela debido a que se pone a leer el socket, y solamente va a hacer eso.
Si deseas que la interfase grafica funcione, debes de crear un "subprograma" para que ejecute la lectura del socket, eso se hace a traves de los threads.
Beto tiene razón revisa el
Beto tiene razón revisa el capitulo de trheads y vera un ejemplo de creación de una gui con subprocesamiento múltiple.
ese "casi"
en esencia es casi lo mismo
Y ese es el problema.
Tu metodo
ejecutarServidor
termina invocandoServerSocket.accept()
y eso bloquea el hilo donde se invoca... y estas invocandoejecutarServidor
desde el EDT (Event Dispatch Thread) de Swing.Utiliza SwingWorker. Si estas en Java 6, ya viene incluido; si estas en Java 5 necesitas usar una clase que viene en una biblioteca externa (no recuerdo cual, pero se llama igual SwingWorker). Con eso puede echar a andar el servidor en un hilo separado, como debe ser, para no trabar la GUI.