Using Sockets to create a group chat system with a graphical interface

In order to create the group chat system using low-level sockets, we will be having three simple steps

1) Creating the user interface

1 We will need to create a folder called “Client” for putting the java files for the client side.

2 Let’s first create a simple graphical interface for the client to send and receive the chat messages:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class mychat{
    public JTextField tx;
    public JTextArea ta;
    public String login="Imed";
    public mychat(String l){
        login=l;        
        
        JFrame f=new JFrame("my chat");
        f.setSize(400,400);        
        
        JPanel p1=new JPanel();
        p1.setLayout(new BorderLayout());
            
        JPanel p2=new JPanel();
        p2.setLayout(new BorderLayout());        
        
        tx=new JTextField();
        p1.add(tx, BorderLayout.CENTER);
        
        JButton b1=new JButton("Send");
        p1.add(b1, BorderLayout.EAST); 
        
        ta=new JTextArea();
        p2.add(ta, BorderLayout.CENTER);
        p2.add(p1, BorderLayout.SOUTH);
        
        f.setContentPane(p2);
        f.setVisible(true);                        
    }
}

3 We need to make a program to create an instance of the interface and starts the client:

public class startclient{

    public static void main(String [] args){
        	   try{
        	        System.out.println("Hello ");        	        
                        mychat c=new mychat("My Name Here");        
	   }catch(Exception e){e.printStackTrace();}
        
    }
}

Once you when you run the code, you shall get the following user interface:
mychat1

4 We need to make a simple event handler for sending a message from the client to the server when the user clicks the send button after typing some text. We must define the instance variable for a BufferedWriter.

    BufferedWriter writer;

5 We need to create the writer object which writes to the server. Within the constructor, we add the following code. The localhost address can be changed to reflect the server address. 5555 is the chosen port number.

        try{
             Socket socketClient= new Socket("localhost",5555);
             writer= new BufferedWriter(new OutputStreamWriter(socketClient.getOutputStream()));
           }catch(Exception e){e.printStackTrace();}

6 Time now to add the action listener to the button b1:

        b1.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent ev){
                    String s=login+" : "+tx.getText();                    
                    try{
                        writer.write(s);
                        writer.write("\r\n");
                        writer.flush(); 
                     }catch(Exception e){e.printStackTrace();}
                }
            }
        );

7 The updated code for mychat.java file would look like :

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class mychat{
    public JTextField tx;
    public JTextArea ta;
    public String login="Imed";
    BufferedWriter writer;
    public mychat(String l){
        login=l;        
        
        JFrame f=new JFrame("my chat");
        f.setSize(400,400);        
        
        JPanel p1=new JPanel();
        p1.setLayout(new BorderLayout());
            
        JPanel p2=new JPanel();
        p2.setLayout(new BorderLayout());        
        
        tx=new JTextField();
        p1.add(tx, BorderLayout.CENTER);
        
        JButton b1=new JButton("Send");
        p1.add(b1, BorderLayout.EAST); 
        
        ta=new JTextArea();
        p2.add(ta, BorderLayout.CENTER);
        p2.add(p1, BorderLayout.SOUTH);
        
        f.setContentPane(p2);
           
        
        try{
                 Socket socketClient= new Socket("localhost",5555);
                 writer= new BufferedWriter(new OutputStreamWriter(socketClient.getOutputStream()));
        }catch(Exception e){e.printStackTrace();}
    
        b1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ev){
                String s=login+" : "+tx.getText();      
                tx.setText("");              
                try{
                    writer.write(s);
                    writer.write("\r\n");
                    writer.flush(); 
                    }catch(Exception e){e.printStackTrace();}
            }
          }
        );
        
        f.setVisible(true);    
    }
}

2) Creating the Chat Server

Time now to create a server to listen to clients sending messages !
1 Create a new folder called “Server“.

2 Inside this folder, create a new java program as Server.java Here is the java source code for a simple socket server

import java.io.*;
import java.net.*;
     
class Server implements Runnable{
    	Socket connectionSocket;     
    	public Server(Socket s){
    		try{
    			System.out.println("Client Got Connected  " );
    			connectionSocket=s;
    		}catch(Exception e){e.printStackTrace();}
    	}     
    	public void run(){
    		try{
    		        BufferedReader reader =
    		        		new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
    		        BufferedWriter writer= 
    		        		new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()));
                        while(true){
                            String data1 = reader.readLine().trim();
                            System.out.println("Received : "+data1);                            
                        }
    		}catch(Exception e){e.printStackTrace();}
       }
       public static void main(String argv[]) throws Exception{
            System.out.println("Threaded Chat Server is Running  " );
            ServerSocket mysocket = new ServerSocket(5555);
             while(true){
                Socket sock = mysocket.accept();
                Server server=new Server(sock);
                Thread serverThread=new Thread(server);
                serverThread.start();
             }
          }
}

3 Feel free now to compile everything, server and client and run both of them. The server needs to be started the first. To compile and run the server

javac Server.java
java Server

4 Now, to compile and run the client, use the following command:

javac startclient.java
java startclient

This is the screenshot from the server side receiving the message from the client:
socket-chat-1

3) Broadcasting Messages to All Clients

We run the program, we would get the following, the server would receive the messages sent by the client. The server now needs to broadcast every received message back to all clients.

1 Within the Server class, we need to create a vector as a static variable to store all clients.

public static Vector clients =new Vector();

2 Once we get a client connected, we would store its BufferedWriter object inside the Vector list.

clients.add(writer);

3 The server needs to iterate through all writer objects and sends the message back to the clients as shown below:

for (int i=0;i<clients.size();i++){
    try{
        BufferedWriter bw= (BufferedWriter)clients.get(i);
        bw.write(data1);
        bw.write("\r\n");
        bw.flush();
    }catch(Exception e){e.printStackTrace();}
}

4 This is the complete server code now :

import java.io.*;
import java.net.*;
import java.util.*;
        
class Server implements Runnable{
            Socket connectionSocket;     
            public static Vector clients=new Vector();
            public Server(Socket s){
                    try{
                            System.out.println("Client Got Connected  " );
                            connectionSocket=s;
                    }catch(Exception e){e.printStackTrace();}
            }     
            public void run(){
                    try{
                            BufferedReader reader =
                                            new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
                            BufferedWriter writer= 
                                            new BufferedWriter(new OutputStreamWriter(connectionSocket.getOutputStream()));
                            
                            clients.add(writer); 
                            
                        while(true){
                            String data1 = reader.readLine().trim();
                            System.out.println("Received : "+data1);      
                            
                            for (int i=0;i<clients.size();i++){
                               try{
                                    BufferedWriter bw= (BufferedWriter)clients.get(i);
                                    bw.write(data1);
                                    bw.write("\r\n");
                                    bw.flush();
                                }catch(Exception e){e.printStackTrace();}
                            }
                        }
                    }catch(Exception e){e.printStackTrace();}
        }
        public static void main(String argv[]) throws Exception{
            System.out.println("Threaded Chat Server is Running  " );
            ServerSocket mysocket = new ServerSocket(5555);
                while(true){
                Socket sock = mysocket.accept();
                Server server=new Server(sock);
                Thread serverThread=new Thread(server);
                serverThread.start();
                }
            }
}

5 On the client side, we need to listen to the server when it sends back message. A better way would be to create a thread running in parallel with the BufferedReader instance. Let’s simplify things first. Define an instance variable of BufferedReader at the mychat class:

  BufferedReader reader;

6 We need to create an instance for the object within the constructor

reader =new BufferedReader(new InputStreamReader(socketClient.getInputStream()));

7 So, here is the code needed for listening to the server and appending messages to the text area on the interface ! The question is where to put it ?

        try{
                String serverMsg=""; 
                while((serverMsg = reader.readLine()) != null){
                    System.out.println("from server: " + serverMsg);
                    ta.append(serverMsg+"\n");
                }
        }catch(Exception e){e.printStackTrace();}
If you put inside the constructor, it may block your application from starting as it contains a blocking code for the Readline. A better way would be to create a thread instead to contain this code.

8 Make sure that mychat implements Runnable and add the above code within the run method. Here is the full code for mychat.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class mychat implements Runnable{
    public JTextField tx;
    public JTextArea ta;
    public String login="Imed";
    BufferedWriter writer;
    BufferedReader reader;
    public mychat(String l){
        login=l;        
        
        JFrame f=new JFrame("my chat");
        f.setSize(400,400);        
        
        JPanel p1=new JPanel();
        p1.setLayout(new BorderLayout());
            
        JPanel p2=new JPanel();
        p2.setLayout(new BorderLayout());        
        
        tx=new JTextField();
        p1.add(tx, BorderLayout.CENTER);
        
        JButton b1=new JButton("Send");
        p1.add(b1, BorderLayout.EAST); 
        
        ta=new JTextArea();
        p2.add(ta, BorderLayout.CENTER);
        p2.add(p1, BorderLayout.SOUTH);
        
        f.setContentPane(p2);
           

           
        try{
                 Socket socketClient= new Socket("localhost",5555);
                 writer= new BufferedWriter(new OutputStreamWriter(socketClient.getOutputStream()));
                 
                 reader =new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
                 

			
		    		
        }catch(Exception e){e.printStackTrace();}
    
    
        b1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent ev){
                String s=login+" : "+tx.getText();  
                tx.setText("");
                try{
                    writer.write(s);
                    writer.write("\r\n");
                    writer.flush(); 
                    }catch(Exception e){e.printStackTrace();}
            }
          }
        );
        
        f.setVisible(true);    
        

    }
    public void run(){
             try{
                String serverMsg=""; 
                while((serverMsg = reader.readLine()) != null){
                    System.out.println("from server: " + serverMsg);
                    ta.append(serverMsg+"\n");
                }
        }catch(Exception e){e.printStackTrace();}   
    }
}

9 You need to modify the startclient.java to create a thread for starting the mychat run code. Here is the modified code for the startclient.java file

    public class startclient{
     
        public static void main(String [] args){
            	   try{
            	        System.out.println("Hello ");        	        
                            mychat c=new mychat("My Name Here");   
                            Thread t1=new Thread(c);
                            t1.start();
    	   }catch(Exception e){e.printStackTrace();}
            
        }
    }