Сервер сокетов в Java, последний подключенный клиент - единственный, кто может прочитать сокет - PullRequest
0 голосов
/ 29 августа 2011

У меня проблема с сервером сокетов, который я разрабатываю.

Сначала сервер сокетов имеет следующий класс:

  • Класс Main_Servidor (Запустите сервер)

  • Класс EjecutarServidor (в основном ожидание новых подключений, а затем запуск их как подпроцесс)

  • Класс ManejoConexion (получает объект сокета из дома, пишет и читает в сокете)

  • Класс Panel_mensajes (Показывает информацию о соединениях сокета в jpanel)

  • Клиент - небольшая программа, написанная на Adobe Air

Проблема в том, что когда два или более клиентов подключены, только последний подключенный клиент может прочитатьразъем.Я уже использовал отладчик eclipse для проверки шаг за шагом, но не могу найти ошибку.

Вот мой код:

Класс Main_Servidor:

public class Main_Servidor {



    public static void main(String[] args) {

        Panel_mensajes PanelMensajes = new Panel_mensajes();
        PanelMensajes.setVisible(true);

        EjecutarServidor ejectuarservidor = new EjecutarServidor();

        ejectuarservidor.ejecutar();

    }

}

Класс EjecutarServidor:

public class EjecutarServidor {

    private static final int puerto = 1025;
    private static final int conexionesMaximas = 3;

    private ExecutorService iniciarThread;
    private static ServerSocket listener;
    private static Socket socket;
    private static boolean EsperarConexiones = true;

    public EjecutarServidor()
    {
        //Crea la pila de sub-procesos y se la asigna al objeto iniciarThread 
        iniciarThread = Executors.newFixedThreadPool(conexionesMaximas);
    }

    public void ejecutar()
    {

        Panel_mensajes.MostrarMensaje("ESPERANDO CONEXIONES...\n\n"); 

        try{

            listener = new ServerSocket(puerto); //Esta a la escucha de nuevas conexiones
                                                 //en el puerto especificado.

            GregorianCalendar fecha = new GregorianCalendar(); //Genera la fecha incluyendo la hora

            while(EsperarConexiones){ //Mientras EsperarConexiones sea TRUE esperará por
                                      //nuevas conexiones.
                socket = null;
                socket = listener.accept(); //Acepta la nueva conexión y la asigna a un objeto socket

                //Muesta en pantalla los datos de la nueva conexión
                Panel_mensajes.MostrarMensaje("NUEVA CONEXION " + 
                        socket.getInetAddress().toString().replace("/", "") + ":" 
                        + socket.getPort() + ", "
                        + fecha.getTime() + "\n" + "\n"
                    );

                //Se crea un nuevo objeto ManejoConexion al cual se le pasa como parametro
                //el objeto socket llamado 'socket' que contiene la nueva conexión
                ManejoConexion con_nva = new ManejoConexion(socket);

                //Ejecuta el nuevo objeto ManejoConexion como un nuevo sub-proceso.
                iniciarThread.execute(con_nva);

            }

        } catch (IOException ioe) {
            Panel_mensajes.MostrarMensaje("IOException en socket!: * " + ioe);
        }
    }

    //Deja de escuchar nuevas peticiones
    public static void cerrarServidor()
    {
        try
        {
            EsperarConexiones = false;
            listener.close();
            socket.close();

        }catch(SocketException SoE)
        {
            Panel_mensajes.MostrarMensaje("SocketException por cerrar servidor, todo OK");
            //SoE.printStackTrace();

        }catch(IOException ioe)
        {
            Panel_mensajes.MostrarMensaje("IOException por cerrar servidor, todo OK");
            //ioe.printStackTrace();
        }finally
        {
            System.exit(0);
        }

    }


}

Класс ManejoConexion:

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

public class ManejoConexion implements Runnable {

    private Socket server;
    private String line;
    private DataInputStream in;
    private static PrintWriter out;
    private static Protocolo proto;
    private static Boolean ACTIVO = true;


    ManejoConexion(Socket server) throws IOException {

        //Recibe un objecto Socket e inicializa la variable server
        this.server = server;

    }

    //Hace que se ejecute un objeto de esta clase como un sub-proceso
    public void run () {

        try {

            //Recibe las tramas de datos desde el servidor
            in = new DataInputStream (server.getInputStream());

            //Envia tramas de datos al servidor
            out = new PrintWriter(server.getOutputStream());

            this.responderPeticiones("+OK");

            //Mantiene abierto el flujo de datos desde el servidor mientras no se cumplan las
            //condiciones.
            Panel_mensajes.MostrarMensaje(Thread.currentThread() + "\n");

            while((line = in.readLine()) != null && !line.equals("TERM")) {

                //Panel_mensajes.MostrarMensaje("CLIENTE " + server.getInetAddress().toString().replace("/", "") + " DICE -> " + line + "\n");
                //proto.entrada(line);

                this.responderPeticiones(line);

                if(!ACTIVO) break;

            }

            this.responderPeticiones("\n" + "CONEXION TERMINADA: " + server.getInetAddress().toString().replace("/", ""));

            Panel_mensajes.MostrarMensaje("\n" + "CONEXION TERMINADA: " + server.getInetAddress().toString().replace("/", "") + "\n" + "\n");
            server.close();

        } catch (IOException ioe) {
            Panel_mensajes.MostrarMensaje("\nIOException AL RECIBIR PETICION: " + ioe.getMessage());
            //ioe.printStackTrace();
        }

    }

    //Se encarga de responder peticiones a los clientes
    public void responderPeticiones(String s) throws IOException
    {
        String input = s;
        String direccion = server.getInetAddress().toString().replace("/", "");

        out.write("SERVIDOR DICE A " + direccion + " -> " + input + "\n");
        out.flush();

    }

    public static void TerminarConexion()
    {
        ACTIVO = false;
        proto = null;

    }

}

(я не добавил класс Panel_mensajes, потому что он не очень актуален)

Ответы [ 3 ]

2 голосов
/ 29 августа 2011

В вашем классе ManejoConexion у вас есть 3 статические переменные, которых не должно быть.Особенно PrintWriter, который будет установлен на выходной поток Socket экземпляра LAST, поэтому первый экземпляр внезапно начнет говорить с последним.и ACTIVO для, но статическая переменная out определенно не должна быть статической.

1 голос
/ 29 августа 2011

Нелегко понять ваш код (я думаю, что он португальский или испанский).Кажется, проблема в EjecutarServidor, у вас есть 3 статических атрибута:

private static ServerSocket listener;
private static Socket socket;
private static Boolean EsperarConexiones

Если подключается новый клиент, вы просто сбрасываете ссылку на прежний сокет клиента:

socket = null;
socket = listener.accept();

Это может не работать, когда несколько клиентов подключаются одновременно, так как ссылка на socket может разрываться между

socket = listener.accept();

и

ManejoConexion con_nva = new ManejoConexion(socket);

Определение listener как статического атрибута определенно нехорошая практика, но должна работать с учетом ваших образцов.Но определение статического socket определенно является ошибкой и может привести к неожиданным результатам.Вы должны переместить объявление Socket в EjecutarServidor.ejecutar(), например:

       while(EsperarConexiones){ 

            Socket socket = listener.accept(); //<-- fix HERE

            Panel_mensajes.MostrarMensaje("NUEVA CONEXION " + 
                    socket.getInetAddress().toString().replace("/", "") + ":" 
                    + socket.getPort() + ", "
                    + fecha.getTime() + "\n" + "\n"
                );

            ManejoConexion con_nva = new ManejoConexion(socket);
            iniciarThread.execute(con_nva);
        }

Исправьте это и посмотрите, не изменит ли оно поведение вашего приложения.

0 голосов
/ 29 августа 2011

Обратите внимание на private static PrintWriter out; в ManejoConexion - оно не должно быть статичным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...