TCP / IP client freezes when sending data to Server

0

It is an "echo" server where I want that when two clients connect, they send a String to the server, the latter answers and the client prints the read.

The fact is that one of them is left unanswered, I use Threads on the server for each client that connects.

Client:

public class Client {
    protected Socket sk;
    public DataOutputStream out;
    public DataInputStream in;
    public Boolean exit=false;

    public Client(String addr, int port) {
        try {
            sk = new Socket(addr, port);

        } catch (Exception e) {
            System.err.println("Cli Socket"+e);
        }
    }

    public void readLines(){

        String line;
        Mess m=null;
        Scanner sc = new Scanner(System.in);
        try {
            in= new DataInputStream(sk.getInputStream());
            out = new DataOutputStream(sk.getOutputStream());
            System.out.print(">>");
            while((line=sc.nextLine()).equals("quit")!= true){
                out.writeUTF(line);
                System.out.println(in.readUTF());
            }
        } catch (Exception e) {
            System.err.println("Cli readlnes:"+e);
            sc.close();
        }finally {
            try {
                if (sc != null) {
                    sc.close();
                }
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
                if (sk != null) {
                    sk.close();
                }
            } catch (IOException e1) {
                System.out.println("Conexión finalizada");
                e1.printStackTrace();
            }
        }

    }

Server:

public class Server {
    public ServerSocket sk;
    protected int port;
    public DataInputStream in;
    public DataOutputStream out;

    public Server(int port){
        this.port=port;
        try {
            sk= new ServerSocket(port);
        } catch (Exception e) {
            System.err.println("Server"+e); 
        }
    }

    public void serve(){
        while(true){
            try {

                System.out.println("Waiting....");
                final Socket csk = sk.accept();
                new Thread(){
                    public void run() { serveClient(csk); }
                }.start();
                System.out.println("Accept connection.."+csk.getLocalAddress()+" "+csk.getPort());

            } catch (Exception e) {
                System.err.println("Srv serve"+e);
            }
        }
    }

    public  void serveClient(Socket sk){        
        String result=null;
        Mess m;
        boolean exit = false;
        try {
            out=new DataOutputStream(sk.getOutputStream());
            in= new DataInputStream(sk.getInputStream());
            while(!exit){           
                    result=in.readUTF();
                    out.writeUTF(result);
          }
        } catch (Exception e) {
            System.err.println("Servecli "+e);
        }   
    }
    
asked by Diego Payo Martinez 01.06.2016 в 11:27
source

1 answer

1

The problem is that the server accepts the client request in the main thread and performs the communication work in an additional thread. Client acceptance should also be in the additional thread, not in the main thread.

The code should look like this:

try {
    new Thread() {
        public void run() {
            System.out.println("Waiting....");
            final Socket csk = sk.accept();
            System.out.println(String.format("Accept connection. %s %s",
                csk.getLocalAddress(), csk.getPort()));
            serveClient(csk);
        }
    }.start();

} catch (Exception e) {
    System.err.println("Srv serve"+e);
}

But this now generates a problem since the code is within a cycle while(true) that will run forever, so that you will have a cycle that will create threads eternally. The best thing for these cases is not to create the threads manually and delegate this work to a pool of threads. ExecutorService is an interface that gives you this functionality and thus you avoid creating this manually:

static final int MAXIMO_HILOS_DEFECTO = 10;

int numeroHilos = MAXIMO_HILOS_DEFECTO;

//...
ExecutorService executor = Executors.newFixedThreadPool(numeroHilos);
while (true) { //<-- esto debería ser una variable, no true
               //lo dejo en true para no complicar más el ejemplo
    executor.submit( new Runnable() {
        @Override
        public void run() {
            System.out.println("Waiting....");
            final Socket csk = sk.accept();
            System.out.println(String.format("Accept connection. %s %s",
                csk.getLocalAddress(), csk.getPort()));
            serveClient(csk);
        }
    });
}
executor.shutdown();

From Java 8, you can reduce the code using lambdas:

executor.submit(() -> {
    System.out.println("Waiting....");
    final Socket csk = sk.accept();
    System.out.println(String.format("Accept connection. %s %s",
        csk.getLocalAddress(), csk.getPort()));
    serveClient(csk);
});
    
answered by 01.06.2016 в 16:54