【问题标题】:Socket server in Java, The last client connected is the only can read the socketJava中的套接字服务器,最后连接的客户端是唯一可以读取套接字的
【发布时间】:2011-08-29 16:08:19
【问题描述】:

我正在开发的套接字服务器有问题。

首先,socket服务器有follow class:

  • Main_Servidor(执行服务器)

  • Class EjecutarServidor(基本上是在等待新的连接,然后作为子进程运行)

  • ManejoConexion(从家里接收一个socket对象,在socket中读写)

  • 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类,因为相关性不大)

【问题讨论】:

    标签: java sockets


    【解决方案1】:

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

    其实我不确定protoACTIVO是干什么用的,但是out这个静态变量绝对不应该是静态的。

    【讨论】:

    • @Guillermo Palafox:您应该重新审视所有静态变量,它们似乎根本没有意义。
    • Jon Lin,谢谢,实际上,静态变量是问题所在,我不知道它们什么时候变成静态的。可能是我在 autofix 中做了 clic ... 坏主意
    【解决方案2】:

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

    解决这个问题,看看它是否会改变您应用的行为。

    【讨论】:

    • 我不知道他们什么时候变成静态的。可能是我在 autofix 中做了 clic,非常感谢!
    【解决方案3】:

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

    【讨论】:

    • 其他几个变量也不应该。仅仅改变这个并不能解决它。
    猜你喜欢
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-24
    相关资源
    最近更新 更多