简体   繁体   English

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

[英]Socket server in Java, The last client connected is the only can read the socket

I have a problem with a socket server that I'm developing. 我有一个我正在开发的套接字服务器的问题。

Firstly, the socket server has then follow class: 首先,套接字服务器遵循类:

  • Class Main_Servidor (Execute the server) Main_Servidor (执行服务器)

  • Class EjecutarServidor (Basically waiting for new connections and then run them as a sub-process) EjecutarServidor类(基本上等待新连接,然后将它们作为子进程运行)

  • Class ManejoConexion (receives a socket object from home, and writes and reads in the socket) ManejoConexion (从home接收套接字对象,并在套接字中写入和读取)

  • Class Panel_mensajes (Shows info about the socket connections in a jpanel ) Panel_mensajes类(显示有关jpanel套接字连接的jpanel

  • The client is a little program written in adobe air 客户端是用adobe air编写的一个小程序

The problem is when two or more clients are connected, only the last connected client can read the socket. 问题是当连接两个或更多客户端时,只有最后连接的客户端才能读取套接字。 I've already used the eclipse's debugger for check step by step, but I can't found the error. 我已经使用eclipse的调试器逐步检查,但我找不到错误。

Here is my code: 这是我的代码:

Main_Servidor Class: 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 Class: 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 Class: 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;

    }

}

(I didn't add the Panel_mensajes class, because is not much relevant) (我没有添加Panel_mensajes类,因为没有多大关系)

In your ManejoConexion class, you have 3 static variables that shouldn't be. 在您的ManejoConexion类中,您有3个不应该是的静态变量。 Especially the PrintWriter , which will be set to the Socket's output stream of the LAST instance, thus the first instance will suddenly start talking to the last one. 特别是PrintWriter ,它将被设置为LAST实例的Socket输出流,因此第一个实例将突然开始与最后一个实例进行通信。

Actually, I'm not sure what proto and ACTIVO are for, but the out static variable should definitely not be static. 实际上,我不确定protoACTIVO的用途,但out静态变量绝对不应该是静态的。

It's not easy to understand your code (I guess it's portuguese or spanish). 理解你的代码并不容易(我猜它是葡萄牙语或西班牙语)。 The problem seems to be in EjecutarServidor , you have 3 static attributes: 问题似乎在EjecutarServidor ,你有3个静态属性:

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

If a new client connects you simply reset the reference to the client former socket by: 如果新客户端连接,您只需通过以下方式重置对客户端套接字的引用:

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

This may not work when several clients connect concurrently as the reference to socket may break between 当多个客户端同时连接时,这可能不起作用,因为对socket的引用可能会中断

socket = listener.accept();

and

ManejoConexion con_nva = new ManejoConexion(socket);

Defining listener as a static attribute is definitely not a good practive, but should work given your samples. listener定义为静态属性绝对不是一个好的实践,但是应该根据您的样本工作。 But defining the static socket is definitely an error and may lead to unexpected results. 但是定义静态socket绝对是一个错误,可能会导致意外的结果。 You should move the Socket declaration into EjecutarServidor.ejecutar() like: 您应该将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);
        }

Fix this and see if it changes your app's behaviour. 修复此问题,看看它是否会改变您应用的行为。

Pay attention to private static PrintWriter out; 注意private static PrintWriter out; in ManejoConexion - it should not be static. 在ManejoConexion中 - 它不应该是静态的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM