Search code examples
javamultithreadingclient-serverjava-threads

Send to a server using a specific active thread


I have this class where i try to create a number of threads and then i need to send a message to the server over all the threads or using a specific thread. I can't seem to find a way to do that in this way I can only send using the last thread that was created.

Here is the class:

 public class test{

  public test(){

  }

  public static void main(String[] args){
    MultiThreadChatClient mc = new MultiThreadChatClient();
    test st =  new test();
    for(int i =0; i<=4; i++){
       mc.createThreads();
     }


    while (true) {

          System.out.print("type your message: ");
          Scanner s = new Scanner(System.in);
          String ss = s.nextLine();
          ss = ss.trim().replaceAll(" +", " ");

            mc.sendMessage(ss);

try 
{
    Thread.sleep(400);
} 
catch(InterruptedException e)
{
     // this part is executed when an exception (in this example InterruptedException) occurs
  System.out.println("Exeption: " + e);
}

     }      
}

}

Here's the Client thread class:

  public class MultiThreadChatClient implements Runnable {

  // The client socket
  private static Socket clientSocket = null;
  // The output stream
  private static PrintStream os = null;
  // The input stream
  private static BufferedReader br;

  private static BufferedReader inputLine = null;
  private static boolean closed = false;


  public static void main(String[] args) {

    // The default port.
    int portNumber = 2222;
    // The default host.
    String host = "localhost";

    if (args.length < 2) {
      System.out.println("Usage: java MultiThreadChatClient <host> <portNumber>\n"
              + "Now using host=" + host + ", portNumber=" + portNumber);
    } else {
      host = args[0];
      portNumber = Integer.valueOf(args[1]).intValue();
    }
  }



    /*
     * Open a socket on a given host and port. Open input and output streams.
     */

    public void createThreads(){
    try {
      clientSocket = new Socket("localhost", 2222);
      inputLine = new BufferedReader(new InputStreamReader(System.in));
      os = new PrintStream(clientSocket.getOutputStream());
      br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    } catch (UnknownHostException e) {
      System.err.println("Don't know about host " + 2222);
    } catch (IOException e) {
      System.err.println("Couldn't get I/O for the connection to the host " + 2222);
    }
  //}

    /*
     * If everything has been initialized then we want to write some data to the
     * socket we have opened a connection to on the port portNumber.
     */
    if (clientSocket != null && os != null && br != null) {

        new Thread(new MultiThreadChatClient()).start();

    }
  }
          public void sendMessage(String mes){
          os.println(mes);
          }

  /*
   * Create a thread to read from the server. (non-Javadoc)
   * 
   * @see java.lang.Runnable#run()
   */
  public void run() {
    /*
     * Keep on reading from the socket till we receive "Bye" from the
     * server. Once we received that then we want to break.
     */
    String responseLine;
    try {
      while ((responseLine = br.readLine()) != null){

        System.out.println(responseLine);

        if (responseLine.indexOf("*** Bye") != -1)
          break;
      }
      closed = true;
    } catch (IOException e) {
      System.err.println("IOException1234:  " + e);
    }
  }
}

Here's the server code:

  public class MultiThreadChatServerSync {

  // The server socket.
  private static ServerSocket serverSocket = null;
  // The client socket.
  private static Socket clientSocket = null;


  // This chat server can accept up to maxClientsCount clients' connections.
  private static final int maxClientsCount = 50;
  private static final clientThread[] threads = new clientThread[maxClientsCount];

  public static void main(String args[]) {

    // The default port number.
    int portNumber = 2222;
    if (args.length < 1) {
      System.out.println("Usage: java MultiThreadChatServerSync <portNumber>\n"
          + "Now using port number=" + portNumber);
    } else {
      portNumber = Integer.valueOf(args[0]).intValue();
    }

    /*
     * Open a server socket on the portNumber (default 2222). Note that we can
     * not choose a port less than 1023 if we are not privileged users (root).
     */
    try {
      serverSocket = new ServerSocket(portNumber);
      //System.out.println(serverSocket.getPort());
    } catch (IOException e) {
      System.out.println(e);
    }

    /*
     * Create a client socket for each connection and pass it to a new client
     * thread.
     */
    while (true) {
      try {
        clientSocket = serverSocket.accept();
        int i = 0;
        for (i = 0; i < maxClientsCount; i++) {
          if (threads[i] == null) {
            (threads[i] = new clientThread(clientSocket, threads)).start();
            //System.out.println("A new client is created");
            break;
          }
        }
        if (i == maxClientsCount) {
          PrintStream os = new PrintStream(clientSocket.getOutputStream());
          os.println("Server too busy. Try later.");
          os.close();
          clientSocket.close();
        }
      } catch (IOException e) {
        System.out.println(e);
      }
    }
  }
}

class clientThread extends Thread {
MultiThreadChatServerSync ms = new MultiThreadChatServerSync();
  private String clientName = null;
  //private DataInputStream is = null;
   private BufferedReader br = null;
  private PrintStream os = null;
  private Socket clientSocket = null;
  private final clientThread[] threads;
  private int maxClientsCount;

  public clientThread(Socket clientSocket, clientThread[] threads) {
    this.clientSocket = clientSocket;
    this.threads = threads;
    maxClientsCount = threads.length;
    //System.out.println("Inside the Client thread");
  }

  public void run() {
    MultiThreadChatServerSync mss = new MultiThreadChatServerSync();
    int maxClientsCount = this.maxClientsCount;
    clientThread[] threads = this.threads;
    //System.out.println("Inside the run");

    try {
      /*
       * Create input and output streams for this client.
       */
      br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
      os = new PrintStream(clientSocket.getOutputStream());




      while (true) {
        String line = br.readLine();
        System.out.println("message received via Client port: " + clientSocket.getPort());
        System.out.println("Received: " + line);

      }

    } catch (IOException e) {
    }
  }
}

So, is there a way to create 5 threads and then send the message over all of them or choose one specific thread out of them?


Solution

  • To be able to have a client which starts several sessions, and to be able to send data to one or several of them, the client must change in a few ways.

    1. The static references in the client must be removed.
    2. The Socket instances must be created and stored in the main thread (the writers will be used to send messages on behalf of one or more client sessions)
    3. Each client session is now only responsible for reading (the reader is passed via the constructor).

    The code is based on your original code, and meant to be a template for further enhancements: It will manage 5 client sessions, and be able to write to 1 or many.

    The new main Thread (As an example, the Scanner will first ask the message for client #1, then 2, 3, 4 and next will broadcast to all, in a loop):

    public class MultiThreadChatClientRunner {
    
    final int NO_CLIENTS = 5;
    //final String HOST_IP = "192.168.2.7";
    final String HOST_IP = "localhost";
    
    public static void main(String[] args) {
    
        new MultiThreadChatClientRunner().start();
    
    }
    
    private void start() {
    
        Socket[] sockets = new Socket[NO_CLIENTS];
        PrintStream[] writers = new PrintStream[NO_CLIENTS];
        BufferedReader[] readers = new BufferedReader[NO_CLIENTS];
    
        for (int i = 0; i < NO_CLIENTS; i++) {
            System.out.println("Creating client number "+i);
            Socket clientSocket;
            try {
                clientSocket = new Socket(HOST_IP, 2222);
                writers[i] = new PrintStream(clientSocket.getOutputStream());
                readers[i] = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                new Thread(new MultiThreadChatClient(i, readers[i])).start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        int clientId = 0;
        Scanner s = new Scanner(System.in);
        while (true) {
    
            System.out.print("type your message for client #"+clientId);
            String ss = s.nextLine();
            ss = ss.trim().replaceAll(" +", " ");
    
            writers[clientId].println(ss);
            clientId = (clientId+1)%NO_CLIENTS;
    
            // Test to broadcast to all clients
            if (clientId == 4) {
                for (int i = 0; i<NO_CLIENTS; i++)
                    writers[i].println("Broadcast message: "+ss);
            }
    
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                System.out.println("Thread was interrupted");
                break;
            }
        }
        s.close();
    }
    
    }
    

    The new client, which is much simpler than before:

    public class MultiThreadChatClient implements Runnable {
    
    // The client socket
    private Socket clientSocket = null;
    // The output stream
    private PrintStream os = null;
    // The input stream
    private final BufferedReader br;
    private final int clientId;
    
    public MultiThreadChatClient(int clientId, BufferedReader br) {
        super();
        this.clientId = clientId;
        this.br = br;
    }
    
    /*
     * Create a thread to read from the server. (non-Javadoc)
     * 
     * @see java.lang.Runnable#run()
     */
    public void run() {
        /*
         * Keep on reading from the socket till we receive "Bye" from the
         * server. Once we received that then we want to break.
         */
        String responseLine;
        try {
            while ((responseLine = br.readLine()) != null) {
    
                System.out.printf("Client #%d received message=%s\n", clientId, responseLine);
    
                if (responseLine.indexOf("*** Bye") != -1)
                    break;
            }
        } catch (IOException e) {
            System.err.println("IOException1234:  " + e);
        }
    }
    }
    

    And the server, which is nearly identical, but manages closes better, and has some more logging to show which client is communicating.

    public class MultiThreadChatServerSync {
    
    // The server socket.
    private static ServerSocket serverSocket = null;
    // The client socket.
    private static Socket clientSocket = null;
    
    // This chat server can accept up to maxClientsCount clients' connections.
    private static final int maxClientsCount = 50;
    private static final ClientThread[] threads = new ClientThread[maxClientsCount];
    
    public static void main(String args[]) {
    
        // The default port number.
        int portNumber = 2222;
        if (args.length < 1) {
            System.out.println(
                    "Usage: java MultiThreadChatServerSync <portNumber>\n" + "Now using port number=" + portNumber);
        } else {
            portNumber = Integer.valueOf(args[0]).intValue();
        }
    
        /*
         * Open a server socket on the portNumber (default 2222). Note that we
         * can not choose a port less than 1023 if we are not privileged users
         * (root).
         */
        try {
            serverSocket = new ServerSocket(portNumber);
            // System.out.println(serverSocket.getPort());
        } catch (IOException e) {
            System.out.println(e);
        }
    
        /*
         * Create a client socket for each connection and pass it to a new
         * client thread.
         */
        while (true) {
            try {
                System.out.println("Awaiting a new connection on "+serverSocket.getLocalPort());
                clientSocket = serverSocket.accept();
                int i = 0;
                for (i = 0; i < maxClientsCount; i++) {
                    if (threads[i] == null) {
                        (threads[i] = new ClientThread(i, clientSocket)).start();
                        // System.out.println("A new client is created");
                        break;
                    }
                }
                if (i == maxClientsCount) {
                    PrintStream os = new PrintStream(clientSocket.getOutputStream());
                    os.println("Server too busy. Try later.");
                    os.close();
                    clientSocket.close();
                }
            } catch (IOException e) {
                System.out.println(e);
            }
        }
    }
    }
    
    class ClientThread extends Thread {
    
    private BufferedReader br = null;
    private PrintStream os = null;
    private final Socket clientSocket;
    private final int clientId;
    
    public ClientThread(int clientId, Socket clientSocket) {
        this.clientSocket = clientSocket;
        this.clientId = clientId;
    }
    
    public void run() {
    
        try {
            /*
             * Create input and output streams for this client.
             */
            br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            os = new PrintStream(clientSocket.getOutputStream());
    
            String line = "";
            while ((line = br.readLine()) != null) {
                System.out.printf("Client <%d> received message=<%s> via Client port: <%d>\n", clientId, line, clientSocket.getPort());
                // Echo it back (as a test)
                os.println(line);
            }
            br.close();
            os.close();
            clientSocket.close();
    
        } catch (IOException e) {
        }
        System.out.println("Client has closed the session");
    }
    }
    

    Let me know if you have any further questions at this time.