Java中的套接字服务器,最后连接的客户端是唯一可以读取套接字的

时间:2011-08-29 16:08:19

标签: java sockets

我正在开发一个正在开发的套接字服务器。

首先,套接字服务器遵循类:

  • 班级Main_Servidor(执行服务器)

  • EjecutarServidor(基本上等待新连接,然后将它们作为子流程运行)

  • ManejoConexion(从home接收套接字对象,并在套接字中写入和读取)

  • 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 个答案:

答案 0 :(得分:2)

ManejoConexion类中,您有3个不应该是的静态变量。尤其是PrintWriter,它将被设置为LAST实例的Socket输出流,因此第一个实例将突然开始与最后一个实例进行通信。

实际上,我不确定protoACTIVO的用途,但out静态变量绝对不应该是静态的。

答案 1 :(得分:1)

理解你的代码并不容易(我猜它是葡萄牙语或西班牙语)。问题似乎在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);
        }

修复此问题,看看它是否会改变您应用的行为。

答案 2 :(得分:-1)

注意ManejoConexion中的private static PrintWriter out; - 它不应该是静态的。