Chat Server

This is the server part of the chat program. I assume that you already know some basic network programming, if you don't, you can read my  network tutorial. You will need to understand the echoserver and the echoclient.

import java.net.*;
import java.io.*;
 

public class ChatServer extends Thread{

    public final int default_PORT=8000;
    Socket sock;
    ServerSocket server;
    ThreadGroup group;
    int nr;

The new thing here is the Thread group, we will need this to identify the chatroom. If you want to modify this program, you can make more ThreadGroups to make multiple rooms. Also we need a number to keep track of the connections.
 public Server(int port){

    group=new ThreadGroup("Chat");
    nr=0;
    try{
        if(port<=0)
          server=new ServerSocket(default_PORT);
        else
          server=new ServerSocket(port);
        }
    catch(IOException ex){}
   }

Now we initialise the ThreadGroup and we give it the name "Chat", but you may ofcourse change that. Other than that we sets nr to 0, and initialize the server to listen to port 8000, if the port number passed to the constructor is 0 and the actuall number if it is greater than 0.
   public void run(){

 setPriority(3);
 while(true){
 try{
  sock=server.accept();
  Connection con=new Connection(sock,group,nr);
  System.out.println("Connection recieved");
  nr++;
  con.start();
  }
 catch(IOException ex){}
     }
 }

First we use the Thread method setPriority(int) to set the priority to 3. This isn't necesary, but the default priority is 5, so we set it down to 3 to make the other programs run better. I tried to run this program with max priority (Tread.MAX_PRIORITY = 10) and that caused the entire system to run extremely slowly, because it was busy executing the server (it took about 2 minutes from the time I clicked to activate a window untill it apeared).
Next we go through the infinite loop, this is because we want multiple connections (no use in a chatroom with only 1 connection). Then we make the server wait for a request, and assign a socket to communicate through. Next we make an object of the class Connection (the other part of the server which we will make a little later). This constructor takes three arguments, one socket, a ThreadGroup and an int. We pass on the objects we created in this class. Note that the ThreadGroup will be the same Object passed on for every connection, this is because we will put all threads (connections) in the same group.
After we printed the message and updated the number, we call the start method in the thread class. This will make the thread execute on its own, by executing the run method. You may think that it would be ok just to call the run method (I did), but when I tried to replace start with run in this program, I got a NullPointerException. That means that I try to refer to an object that is not initialized.
public static void main(String args[]){

    int port=0;
    if(args.length<1){
        System.out.println("\nServer will listen to port 8000");
        }
    else{
         try{
             port=Integer.parseInt(args[0]);
          }
         catch(NumberFormatException e){
    System.out.println("Port argument must be a Integer");
    System.out.println("Server will listen to port 8000");
      }}
  Server s=new Server(port);
  s.start();
     }
  }

Here we just Start up the server program, and make it listen to port 8000 if none or an illegal portnumber has been passed at the command line, otherwise we start up at the userspecified port.
class Connection extends Thread{

 Socket sock;
 InputStream in;
 OutputStream out;

This is the second class of the Server program, I called it Connection, but this is a bad name since there is an interface in another package which is called Connection. You may wanna change it, but it will work out fine this way too.

We need a socket, an InputStream and a OutputStream, to communicate. This class also extends the Thread class, so that it can belong to a ThreadGroup.

public Connection(Socket s,ThreadGroup tg,int nr){

    super(tg,"connection nr:"+nr);
    sock=s;
    try{
         in=sock.getInputStream();
         out=sock.getOutputStream();
        }
    catch(IOException ex){}
    }

This constructor takes Three arguments, a socket, The ThreadGroup to which it shall belong, and the number of the connection (This is just so that all the threads will get different names). First we call the constructor of the superclass with the super(ThreadGroup,String) call. The call to the constructor of the super class must always be the first call of the constructor, if not java will automaticly call the default constructor (the one that takes no arguments). I this case that would be no good, because we want to assign this thread to a group. This Group will be the same for every connection. In the try/catch clause we just assign the input and output Streams.
public void run(){

    String line="";
    int tmp=0;
    try{
        while(true){

            while((tmp=in.read())!=(char)'\n'){
            line+=String.valueOf((char)tmp);
      }

Again we divide this method in two since it so long. First we make and empty String and an int which we give the value 0. Then we make the try statement first and then we the infinite while loop. This is important, because if an exception appears, we must jump out of the while loop (of course it could be done different, but this is the easiest way in my opinion). Then we read from the inputsocket, one value (int) at the time, convert it to a char and add it to the String. This goes on untill we reciev newline character, if we don't recieve that (ie. none of the clients are sending data) the thread will block. This is actually a good thing, because if a client closes the connection while the method is reading from the stream, we will get an exception and we are able to get out of "infinite" while loop.
 if(!(line.equals(""))){
  send(line);
  line="";
  }
  }
 }
 catch(IOException ex){}
 finally{try{
      in.close();
      out.close();
      sock.close();}
  catch(IOException e){}}//end finally
 }
Now we must send the string entered to all the clients connected. We will only bother to do this as long as we have a line to send (the if statement), this will prevent the user from sending a lot of empty lines, bothering the other users (You have probably seen some people getting a kick out of hitting return a lot of times, making it imposible for the other users to read each others messages). Next we pass the line to the send method, after that one is excuted the program will continue with erasing the line. At last, if we get an exception, we clean up.
public void send(String line){

    ThreadGroup g=getThreadGroup();
    int lengde=line.length();
    int ant=g.activeCount();
    Connection c[]=new Connection[ant];
    g.enumerate(c,false);
    for(int i=0;i<ant;i++)
      c[i].write(line,lengde);
     }

Now for the send method, here we demonstrate some of the beuty about multithreading. First assign this thread group to an variable called g, then we find the number of characters in the line (I called this variable "lengde" which is the Norwegian word for length). The variable "ant", which we get from the method ThreadGroup.activeCount(), is the number of threads in this threadgroup who are active, we need this soon. Now we create an array of Connection objects, the number of elements in this array is, as you may see, the same number as there are active threads. The enumerate(thread[], boolean) method (it actually returns an int, but we don't care about that) copies each thread into the array, if the array is shorter than the number of threads (Its not here, because we got the number for the array from the ThreadGroup itself), the last threads will just be ignored. You may notice that I use the name Connection and thread as if they were the same. Well you're right, I do, thats because Connection is a thread. Just remember that a thread don't have to be a connection (it depends on the subclassing, but don't worry about it, it may get rather confusing). Next we run through a for so we can call the write method in each thread/connection object, we must pass the line and the length of the line, I'll show you why now.
public void write(String line,int lengde){

    try{
        for(int i=0;i<lengde;i++)
           out.write((int)line.charAt(i));
       out.write((int)'\n');
        }
    catch(IOException e){}
   }
 

}//End of class

This is the write method, the reason for passing the length of the line is that the for loop will write that many character to the OutputStream. When all the characters in the line has been written, we need to write a newline character, since we use this to show that the line has come to an end.
In the send method, we called this method for all of the threads. This means that all of the chat members shall recieve the message. Now, just write the program in a texteditor, save the source in a file called ChatServer.java (You can also save the source codes of the two classes in two different files. Your choice), and then compile it, and move onto the  ChatClient program.
Remember to visit the sponsors at my  homepage.