4

I am making a TCP chat server from a simple tutorial I found and I'm kind of new to java. I will eventually make a client class but I've been testing it through telnet so far. I have a couple of problems. I have setup the server to take commands from the client. For example "EXIT" which closes the client connection, and "Username" which prints "OK". Shown below:

USER 1: TIM

Welcome to Bob's Chat Server!

Please Enter a User Name: 
Tim
Welcome Tim we hope you enjoy your chat today
Bob:Hello
Hi Bob
Tim
OK
EXIT
Closing Connection  . . . Goodbye

USER 2: BOB

Welcome to Bob's Chat Server!

Please Enter a User Name: 
Bob
Welcome Bob we hope you enjoy your chat today
Hello
Tim:Hi Bob
Tim:Tim

I have three problems that I want to address:

  1. You'll notice that when USER 1 typed "Tim" (his username) it said "OK" like I wanted, but it also printed "Tim" to USER 2. Is there a way to make it not send my typed commands across? So when I type "Tim" it doesn't print "Tim" to USER 2?

  2. When messages are sent to other users it displays who said it. Is there a way to print the name on both connections? For example when USER 2 says "Hello" it looks more like "Bob: Hello" on both connections?

  3. Is there a way to keep track of everything that's said in the entire chat session and print off the entire contents of the chat to whatever user requested it?

Here is my server code:

// Chat Server runs at port no. 9020
import java.io.*;
import java.util.*;
import java.net.*;
import static java.lang.System.out;

public class  TCPServer 
{
  Vector<String> users = new Vector<String>();
  Vector<HandleClient> clients = new Vector<HandleClient>();

  int PORT = 9020;
  int NumClients = 10;

  public void process() throws Exception  
  {
      ServerSocket server = new ServerSocket(PORT,NumClients);
      out.println("Server Connected...");
      while( true) 
      {
         Socket client = server.accept();
         HandleClient c = new HandleClient(client);
         clients.add(c);
     }  // end of while
  }

  public static void main(String ... args) throws Exception 
  {
      new TCPServer().process();
  } // end of main

  public void boradcast(String user, String message)  
  {
        // send message to all connected users
        for (HandleClient c : clients)
           if (!c.getUserName().equals(user))
           {
              c.sendMessage(user,message);
           }
  }

  class HandleClient extends Thread 
  {
    String name = "";
    BufferedReader input;
    PrintWriter output;

    public HandleClient(Socket client) throws Exception 
    {
          // get input and output streams
         input = new BufferedReader(new InputStreamReader(client.getInputStream())) ;
         output = new PrintWriter (client.getOutputStream(),true);
         output.println("Welcome to Bob's Chat Server!\n");
         // read name
         output.println("Please Enter a User Name: ");
         name  = input.readLine();
         users.add(name); // add to vector
         output.println("Welcome "+name+" we hope you enjoy your chat today");
         start();
    }

    public void sendMessage(String uname,String  msg)  
    {
        output.println( uname + ":" + msg);
    }

    public String getUserName() 
    {  
        return name; 
    }

    public void run()  
    {
         String line;
         try    
         {
            while(true)   
            {
                        line = input.readLine();
                if("EXIT".equals(line))
            {
                output.println("Closing Connection  . . . Goodbye");
                            clients.remove(this);
                        users.remove(name);
                break;
                    }
            else if(name.equals(line))
            {
                            output.println("OK");
                    }
                boradcast(name,line); // method  of outer class - send messages to all
            }// end of while
         } // try
         catch(Exception e) 
         {
           System.out.println(e.getMessage());
         }
    } // end of run()
  } // end of inner class
} // end of Server

Any help is appreciated. Thanks.

user1174834
  • 239
  • 3
  • 7
  • 14

2 Answers2

2

I had modified your code as per your liking , do have a look :

For Point 1:

public void run()  
    {
         String line;
         try    
         {
            while(true)   
            {
                        line = input.readLine();
                if("EXIT".equals(line))
                {
                    output.println("Closing Connection  . . . Goodbye");
                    clients.remove(this);
                    users.remove(name);
                    break;
                }
                else if(name.equals(line))
                {
                    output.println("OK");
                }
                else
                {
                    // Seems to me just adding this else part will do the trick for point one.
                    boradcast(name,line); // method  of outer class - send messages to all
                }
            }// end of while
         } // try
         catch(Exception e) 
         {
           System.out.println(e.getMessage());
         }
    }

For Point 2 :

Seems to me in this you are typing to the console to get the input, in that case atleast for once you have to type what you have to send to the other side, then you can add your modification to this as shown in the first line of the method, broadcast();, so that you can satisfy your need for Point 2, or (else You can let the server side send it back to the client, the message which containts the name, it will be like a client send his message to the server and the server is sending all the clients back.)

public void boradcast(String user, String message)  
{
    System.out.println(user + " : " + message);
    // send message to all connected users
    for (HandleClient c : clients)
    if (!c.getUserName().equals(user))
    {
        c.sendMessage(user,message);
    }
}

And for Point 3, you can write your conversation to the file or save it to the database, which ever way is appropriate to you.

And since you said you are new to Java, you better look at java.nio. This package is better than the previous java.io package.

LATEST EDIT :

Try this small sample code, hope this might do what you asking for :

import java.io.*;

public class StringConsole
{
    public static void main(String... args) throws IOException
    {
        int count = 0;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while (count < 5)
        {
            System.out.print("My Name : ");
            String message = br.readLine();
            count++;
        }   
    }
}

Hope this might help you in some way.

Regards

nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • Thanks these suggestions they helped a lot. I have one more quick question. How can I make it display the user's name before the cursor? For example after user enters a name the cursor always displays "Username:" and then the cursor starts afterword. – user1174834 Jan 30 '12 at 04:33
  • @user1174834 : If you using console, it's a bit tough, do check my latest edit, that can somewhat do that for you. Regards – nIcE cOw Jan 30 '12 at 05:38
  • I don't know if I'm supposed to create a new thread, but I have another question? I have implemented the changes you suggested and they work great. I want to add two other commands. "PUSH" and "GET". So when a user types "PUSH: + some string" it stores that string to an array or vector or something and displays "OK". When the user types "GET" it just displays the content of that array with a "\n" at the beginning of each name, separating the sentences by the user's names. I hope that's clear enough. I want to avoid writing the contents to a file I think. – user1174834 Jan 30 '12 at 17:14
  • @user1174834 : Seems like what you doing, will end up making your code complex, with loads of conditions to check at. I am really not a master, but can give you a small hint, that using different sockets for each task can make your work easier. IF you like I can give you a sample code for that. Regards – nIcE cOw Jan 30 '12 at 17:19
  • @user1174834 : Why not try your hands on Swing with this project of yours, instead of adding so many conditions, in swing you can do that on the click of a Button instead of adding complexity to your code. – nIcE cOw Jan 30 '12 at 17:32
  • @user1174834 : Or else if you wanted to stick to your approach for the time being, then do this first : line = line.trim() then do this : if ((line.substring(0, 4)).equals("PUSH")) then store line.substring(5, line.length()); since at index 4 you have a colon ":", and for GET you can simply use a for loop which will print something like ("\n" + array[0];). Regards – nIcE cOw Jan 30 '12 at 17:43
1

Is there a way to make it not send my typed commands across? So when I type "Tim" it doesn't print "Tim" to USER 2?

You already store the user name in HandleClient; when its run method gets input, it checks to see if the user has typed his name. So don't call broadcast if he does that, or if he enters a command.

When messages are sent to other users it displays who said it. Is there a way to print the name on both connections? For example when USER 2 says "Hello" it looks more like "Bob: Hello" on both connections?

Most chat clients I've seen have a multiline window to hold the conversation and a small one for entering text. The user enters his text in the small window, and the server broadcasts it back to him. So the server can prepend the username and colon before each message as it is broadcast, and that will be separate from what the user types in on his own client.

Is there a way to keep track of everything that's said in the entire chat session and print off the entire contents of the chat to whatever user requested it?

Sure. Write it all to a file as you go. Look at java.io.FileWriter.

arcy
  • 12,845
  • 12
  • 58
  • 103