user2893681
user2893681

Reputation: 55

Multi threaded chat server

I am new to Threads. I am trying to broadcast message from the server to clients.but I cannot. It seems like the server is always listen to a new connection.But I can send messages to other clients using the clients terminal. My question is how to allow input while listening at the same time. Here is the code.

MultiThreadChatServerSync.java

import java.io.InputStreamReader;
import java.io.DataInputStream;
import java.io.PrintStream;
import java.io.IOException;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.BufferedReader;

public class MultiThreadChatServerSync extends Thread {

   private static ServerSocket serverSocket = null;
   private static Socket clientSocket = null;
   private static Socket serversSocket = null;
   private static DataInputStream iss = null;
   private static PrintStream oss = null;

   private static final int maxClientsCount = 10;
   private static final clientThread[] threads = new clientThread[maxClientsCount];

   public static void main(String args[]) {
      int num = 0;
      int portNumber = 2222;
      if (args.length < 1) {
         System.out.println("Usage: java MultiThreadChatServerSync<portNumber> "Nowusingnumber=" + portNumber);
      } else {
         portNumber = Integer.valueOf(args[0]).intValue();
      }
      try {
         serverSocket = new ServerSocket(portNumber);
      } catch (IOException e) {
         System.out.println(e);
      }
      DataInputStream iss = null;
      while (true) {
         try {
            System.out.println("5");

            num++;

            // I want to be able to input text here to the server which will be
            // send to different clients
            // But I cannot

            clientSocket = serverSocket.accept();
            int i = 0;
            for (i = 0; i < maxClientsCount; i++) {
               if (threads[i] == null) {
                  System.out.println("6");
                  (threads[i] = new clientThread(clientSocket, threads))
                        .start();
                  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 String clientName = null;
   private DataInputStream is = 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;
   }

   public void run() {
      int maxClientsCount = this.maxClientsCount;
      clientThread[] threads = this.threads;

      try {

         is = new DataInputStream(clientSocket.getInputStream());
         os = new PrintStream(clientSocket.getOutputStream());
         String name;
         while (true) {
            os.println("Enter your name.");
            name = is.readLine().trim();
            if (name.indexOf('@') == -1) {
               break;
            } else {
               os.println("The name should not contain '@' character.");
            }
         }

         os.println("Welcome " + name
               + " to our chat room.\nTo leave enter /quit in a new line.");
         synchronized (this) {
            for (int i = 0; i < maxClientsCount; i++) {
               if (threads[i] != null && threads[i] == this) {
                  clientName = "@" + name;
                  break;
               }
            }
            for (int i = 0; i < maxClientsCount; i++) {
               if (threads[i] != null && threads[i] != this) {
                  threads[i].os.println("*** A new user " + name
                        + " entered the chat room !!! ***");
               }
            }
         }

         while (true) {
            String line = is.readLine();
            if (line.startsWith("/quit")) {
               break;
            }

            if (line.startsWith("@")) {
               String[] words = line.split("\\s", 2);
               if (words.length > 1 && words[1] != null) {
                  words[1] = words[1].trim();
                  if (!words[1].isEmpty()) {
                     synchronized (this) {
                        for (int i = 0; i < maxClientsCount; i++) {
                           if (threads[i] != null && threads[i] != this
                                 && threads[i].clientName != null
                                 && threads[i].clientName.equals(words[0])) {
                              threads[i].os.println("<" + name + "> "
                                    + words[1]);

                              this.os.println(">" + name + "> " + words[1]);
                              break;
                           }
                        }
                     }
                  }
               }
            } else {

               synchronized (this) {
                  for (int i = 0; i < maxClientsCount; i++) {
                     if (threads[i] != null && threads[i].clientName != null) {
                        threads[i].os.println("<" + name + "> " + line);
                     }
                  }
               }
            }
         }
         synchronized (this) {
            for (int i = 0; i < maxClientsCount; i++) {
               if (threads[i] != null && threads[i] != this
                     && threads[i].clientName != null) {
                  threads[i].os.println("*** The user " + name
                        + " is leaving the chat room !!! ***");
               }
            }
         }
         os.println("*** Bye " + name + " ***");

         synchronized (this) {
            for (int i = 0; i < maxClientsCount; i++) {
               if (threads[i] == this) {
                  threads[i] = null;
               }
            }
         }

         is.close();
         os.close();
         clientSocket.close();
      } catch (IOException e) {
      }
   }
}

Upvotes: 1

Views: 2230

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285430

  1. You should listen for clients in a background thread. Your code is not doing this currently and so your server is in fact locked in an endless while (true) loop.
  2. You should refactor your code so that your methods are not so large and unwieldy.
  3. You should refactor your code so that your main method is very brief, so that it simply winds the watch and starts it running, so to speak.
  4. Your code as formatted is very difficult to read. Please consider editing your post and fixing your indentation style so that it is uniform and consistent. I usually avoid using tabs for indenting (forum software often doesn't play well with tabs) and indent each code block 4 spaces.
  5. You almost never want to have your class extend Thread. Instead, have it implement Runnable (or use Rod_Algonquin's excellent recommendation).
  6. Don't use deprecated methods such as DataInputStream#readLine(...) as this could be dangerous to do.

For example, your main could be as simple as this...

public static void main(String[] args) {
   MyServer myServer = new MyServer();
   myServer.getThingsRunning();
}

Edit
Note added as a warning: I don't generally work with sockets, serversockets, or create chat programs, and I'm still new at using Executors, but you could structure your code something along these lines...

public class MultiServer implements Runnable {
   public static final int PORT_NUMBER = 2222;
   private static final int THREAD_POOL_COUNT = 20;
   private List<MultiClient> clientList = new ArrayList<>();
   private ServerSocket serverSocket;
   private ExecutorService clientExecutor = Executors.newFixedThreadPool(THREAD_POOL_COUNT);

   public MultiServer() throws IOException {
      serverSocket = new ServerSocket(PORT_NUMBER);
   }

   @Override
   public void run() {
      // embed your socket acceptance loop in a Runnable's run method
      while (true) {
         try {
            Socket clientSocket = serverSocket.accept();
            MultiClient client = new MultiClient(clientSocket);
            clientList.add(client);
            clientExecutor.execute(client);
         } catch (IOException e) {
            // TODO notify someone of problem!
            e.printStackTrace();
         }
      }
   }

   // ..... more methods and such

   public static void main(String[] args) {
      try {
         MultiServer multiServer = new MultiServer();
         new Thread(multiServer).start();
      } catch (IOException e) {
         e.printStackTrace();
      }

   }
}

Upvotes: 4

Related Questions