Java client hangs if I open two clients at once

Tags: , ,



I’m trying to build a chat-like thing, and the idea is that whenever someone types, it gets sent and printed on every client connected.

If I only open the server and one client, everything runs smoothly — whenever I send something from the client, it goes to the server and then it comes back and gets printed on the client.

Problem is: when I open a second client, only the first message sent afterwards gets printed (on the second client), and then it hangs. It doesnt error message or crash, it just hangs, as if stuck on an infinite loop that does nothing. Meanwhile, the first client stays working as intended.

Client:

package main;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Client extends javax.swing.JFrame 
{
    private Socket client;

    public Client() throws IOException
    {
        initComponents();
        initClient();
        Chat();
    }

    private void initClient()
    {
        try 
        {
            client = new Socket("127.0.0.1",25565);
        } 
        catch (IOException ex) 
        {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private void Chat()
    {
        new Thread() 
        {
            @Override
            public void run() 
            {      
                while (true)
                {      
                    try 
                    {     
                        DataInputStream msg = new DataInputStream(client.getInputStream());
                        
                        if (chat.getText().equals("")) chat.setText(msg.readUTF());
                        else chat.setText(chat.getText() + "n" + msg.readUTF());         
                    } 
                    catch (IOException ex) 
                    {
                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }.start();
    }
    
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane2 = new javax.swing.JScrollPane();
        msgArea= new javax.swing.JTextArea();
        sendMsgButton = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        chat = new javax.swing.JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        msgArea.setColumns(20);
        msgArea.setRows(10);
        jScrollPane2.setViewportView(msgArea);

        sendMsgButton.setText("Send message");
        sendMsgButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
        sendMsgButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendMsgButtonActionPerformed(evt);
            }
        });

        chat.setColumns(20);
        chat.setRows(5);
        chat.setToolTipText("");
        chat.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createCompoundBorder(), "Conversas:", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.ABOVE_TOP));
        chat.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
        jScrollPane1.setViewportView(chat);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane1)
                    .addComponent(jScrollPane2))
                .addContainerGap())
            .addGroup(layout.createSequentialGroup()
                .addGap(142, 142, 142)
                .addComponent(sendMsgButton, javax.swing.GroupLayout.PREFERRED_SIZE, 121, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(147, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 312, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(sendMsgButton, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void sendMsgButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendMsgButtonActionPerformed
        try 
        {
            PrintStream out = new PrintStream(client.getOutputStream());
            out.println("User: " + msgArea.getText());
            msgArea.setText("");
        } 
        catch (IOException ex) 
        {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_sendMsgButtonActionPerformed

    public static void main(String args[])
    {
        try 
        {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) 
            {
                if ("Nimbus".equals(info.getName())) 
                {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } 
        catch (ClassNotFoundException ex) 
        {
            java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } 
        catch (InstantiationException ex) 
        {
            java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } 
        catch (IllegalAccessException ex) 
        {
            java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } 
        catch (javax.swing.UnsupportedLookAndFeelException ex) 
        {
            java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        java.awt.EventQueue.invokeLater(() -> {
            try {
                new Client().setVisible(true);
            } catch (IOException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }
        });        
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextArea msgArea;
    private javax.swing.JButton sendMsgButton;
    private javax.swing.JTextArea chat;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    // End of variables declaration//GEN-END:variables
}

Server:

package main;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList; 
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Server
{     
    private static ArrayList<ClientHandler> clients = new ArrayList<>();
    private static ExecutorService pool = Executors.newFixedThreadPool(5);
    
    public static void main(String args[])
    {  
        int door = 25565;
        
        try 
        {
            ServerSocket server = new ServerSocket(porta, 0, InetAddress.getByName("127.0.0.1"));
            System.out.println("Server running on " + server.getInetAddress().getHostAddress() + ":" + door);

            while (true)
            {
                Socket client = server.accept();
                System.out.println("Client conectado do IP " + client.getInetAddress().getHostAddress());
                ClientHandler clientThread = new ClientHandler(client, clients);
                clients.add(clientThread);

                pool.execute(clientThread);
            }        
        } 
        catch (IOException ex) 
        {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }   
}

ClientHandler: (used by Server)

package main;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ClientHandler implements Runnable
{
    private Socket client;
    private Scanner in ;
    private DataOutputStream out;
    private ArrayList<ClientHandler> clients;
    
    public ClientHandler(Socket clientSocket, ArrayList<ClientHandler> clients) throws IOException
    {
        this.client = clientSocket;
        this.clients = clients;
        in = new Scanner(cliente.getInputStream());
        out = new DataOutputStream(cliente.getOutputStream());
    }
    
    private void sendToAll(String message) throws IOException
    {
        for (ClientHandler Client : clients)
        {
            Client.out.writeUTF(message);
        }
    }
    
    @Override
    public void run() 
    {
        while(in.hasNextLine())
        {
            try 
            {
                String msg = in.nextLine();
                System.out.println(msg);
                sendToAll(msg);
            } 
            catch (IOException ex) 
            {
                Logger.getLogger(ClientHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        try 
        {
            out.close();
            in.close();
        } 
        catch (IOException ex) 
        {
            Logger.getLogger(ClientHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Answer

To answer my own question: the problem lies on using JTextArea, which has some weird interactions with long strings or something.

I swapped it for a JTextPane and now everything works fine.



Source: stackoverflow