Search code examples
javachatmulticast

Why my java multicast clientserver chat work with only one client at the time?


as I said, i'm tring to do a chat for sevral clients, and one server in java. However, it seems that only one client at the time can connect on the server, and I really don't know why (i'm a begginer in this field).

I have 4 classes, here are they :

MainClient :

package Multicast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class MainClient {

    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 5000)){
            BufferedReader input = new BufferedReader(new java.io.InputStreamReader(socket.getInputStream())); 
            PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
            Scanner scanner = new Scanner(System.in); 
            
            String userInput;
            String reponse;
            String clientName = "none";
            
            ClientThread clientThread = new ClientThread(socket);
            clientThread.start();
            
            do {
                if(clientName.equals("none")) {
                    System.out.println("please enter your name");
                    userInput = scanner.nextLine();
                    clientName = userInput;
                    output.println(userInput);
                }
                else {
                    String message = ("|"+clientName +"| :");
                    //System.out.println(message);
                    userInput = scanner.nextLine();
                    output.println(message + " " + userInput);
                    
                    if (userInput.equals("exit")) {
                        break;
                    }
                }
            }while (!userInput.equals("exit"));
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

ClientThread :

package Multicast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class ClientThread extends Thread{
    
    private Socket socket;
    private BufferedReader input;
    
    public ClientThread(Socket s) throws IOException {
        this.socket = s;
        this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        
    }
    
    @Override
    public void run() {
        try {
            while(true) {
                String reponse = input.readLine();
                System.out.println(reponse);
            }
        }
        catch(IOException e){
            e.printStackTrace();
        }
        finally {
            try {
                input.close();
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
}

MainServer :

package Multicast;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class MainServeur {
    public static void main(String[] args) {
        ArrayList<ServerThread> threadList = new ArrayList<>();
        try(ServerSocket serverSocket = new ServerSocket(5000)){
            Socket socket = serverSocket.accept();
            ServerThread serverThread= new ServerThread(socket, threadList);
            threadList.add(serverThread);
            serverThread.start();
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

and ServerThread :

package Multicast;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;

public class ServerThread extends Thread{
    private Socket socket;
    private ArrayList<ServerThread> threadList;
    private PrintWriter output;
    
    public ServerThread(Socket socket, ArrayList<ServerThread> threads) {
        this.socket = socket;
        this.threadList = threads;
        
    }
    
    @Override
    public void run() {
        try {
            BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            output = new PrintWriter(socket.getOutputStream(), true);
            
            while(true) {
                String outputString = input.readLine();
                if(outputString.equals("exit")) {
                    break;
                }
                printToAllClients(outputString);
                System.out.println("Server received : " + outputString);
                
            }
        }
        catch(Exception e) {
            System.out.println("error occured in main of server : "+ e.getStackTrace());
        }
    }
    
    private void printToAllClients(String outputString) {
        for(ServerThread sT : threadList) {
            sT.output.println(outputString);
        }
    }

}

when i try to connect a second client, this error occurs :

java.net.BindException: Cannot assign requested address: connect
    at java.base/sun.nio.ch.Net.connect0(Native Method)
    at java.base/sun.nio.ch.Net.connect(Net.java:579)
    at java.base/sun.nio.ch.Net.connect(Net.java:568)
    at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:588)
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
    at java.base/java.net.Socket.connect(Socket.java:633)
    at java.base/java.net.Socket.connect(Socket.java:583)
    at java.base/java.net.Socket.<init>(Socket.java:507)
    at java.base/java.net.Socket.<init>(Socket.java:287)
    at Multicast.MainClient.main(MainClient.java:13)

I followed this tutorial, thanks a lot and sorry if the post is too long.

Edit : My problem is solved, here are the changes :

package Multicast;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class MainServeur {
    public static void main(String[] args) {
        ArrayList<ServerThread> MyThread = new ArrayList<>();
        try (ServerSocket serverSocket = new ServerSocket(5000)) {
            for (;;) {
                Socket socket = serverSocket.accept();
                ServerThread s = new ServerThread(socket, MyThread);
                MyThread.add(s);
                s.start();
            }
        } catch (IOException e) {
            e.printStackTrace();;
        }
    }
}

Solution

  • You should have one ServerSocket that accepts one client after another in a loop, on the specified port 5000.

    The session then is handled in an other thread, so the next client can be accepted (waited upon).

    public class MainServeur {
        public static void main(String[] args) {
            try (ServerSocket serverSocket = new ServerSocket(5000)) {
                for (;;) {
                    Socket socket = serverSocket.accept();
                    new ServerThread(socket).start();
                }
            } catch (IOException e) {
                System.getLogger(MainServeur.class.getName()).error(e);
            }
        }
    }
    

    Rather than elementary using a Thread, you can use ExecutorServices.

    ThreadPoolExecutor executor = (ThreadPoolExecutor) executors.newFixedThreadPool(50);
    

    That goes beyond the question asked, but allows thread pools limiting the number of clients, wait for all threads to end and more.