Chat Server
Client
The server and the client applications are in separate packages - chat_cl and chat_srv.
The client includes an internal class Gui implementing the graphical interface - a frame which contains a scrolling pane to show messages from the server, and a text field to write messages. The scrolling pane is created on a text area. The text field is linked to an action listener. The listener reads the message, call a method to send it to the server and clear the text field for a new message.
The method "send" verify if the message is empty . In this case, it ask for confirmation to exit the chat. If the message is not empty, the method complements it with the client's name and send it to the server.
The constructor of class "Client" run a method "init" to create the connection to the server and call the constructor of the graphical interface.
It is important to note that the client needs a second thread to read asynchronously and display the messages from the server. This thread is started at the end of the constructor of graphical interface.
package chat_cl;
import java.net.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
import javax.swing.*;
public class Client {
BufferedReader in;
PrintWriter out;
Socket socket;
String name;
Gui g;
Client(JFrame f){
init();
g = new Gui(f);
}
class Gui{
JTextArea serv;
JTextField cl;
Gui (JFrame f){
f.setLayout(new BorderLayout());
serv = new JTextArea(20,10);
serv.setEditable(false);
serv.setBackground(new Color(230,230,230));
serv.setFont(new Font("SANS_SERIF", Font.BOLD, 14));
cl = new JTextField(30);
f.add("Center",new JScrollPane(serv));
f.add("South",cl);
cl.addActionListener(new SrvL());
(new Rcv()).start();
}
class SrvL implements ActionListener{
public void actionPerformed(ActionEvent e){
try{
String st=cl.getText();
send(st);
cl.setText("");
}
catch (Exception ex){
System.out.println("exception: "+ex);
System.out.println("closing...");
try{
socket.close();
}
catch (Exception expt){
System.out.println(expt);
}
}
}
}
class Rcv extends Thread{
public void run(){
for(;;){
try {
sleep(400);
} catch (InterruptedException e){}
try{
serv.append(in.readLine()+"\n");
serv.setCaretPosition(serv.getDocument().getLength());
} catch (IOException e1){break;}
}
System.out.println(" closing reading thread...");
try{
socket.close();
}
catch (Exception expt){
System.out.println(expt);
}
System.exit(0);
}
}
}
public void init(){
try{
do{
name = JOptionPane.showInputDialog("Please enter your name");
} while((name == null)|| (name.length()==0));
String server = null;
InetAddress addr = InetAddress.getByName(server);
System.out.println("addr = " + addr);
socket = new Socket(addr, 9393);
System.out.println("socket = " + socket);
in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
// Output is automatically flushed
// by PrintWriter:
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),true);
out.println(name); // sending client's name to the server
}
catch (java.net.ConnectException ce) {
System.out.println("no server running - closing the client");
System.exit (4);
}
catch (Exception e){
System.out.println("exception: "+e);
System.out.println("closing...");
try{
socket.close();
}catch (Exception e2){
System.out.println("no server running");
System.exit(5);
}
}
}
void send(String s){
if(s.length()==0){
int quit = JOptionPane.showConfirmDialog(null, "Exit chat");
if(quit == 0) {
out.println("END");
System.out.println("closing...");
try{
socket.close();
}
catch (Exception expt){
System.out.println(expt);
}
System.exit(0);
}
}
else out.println(name+": "+s);
}
public static void main(String[] args )throws IOException{
JFrame frame =new JFrame();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
Client cl = new Client(frame);
frame.setTitle(cl.name + " (empty line to exit)");
frame.setSize(500,300);
frame.setVisible(true);
}
}Server chat - created by using ArrayList
An object from class "Client" keeps the information for a connected client - his name and the corresponding PrintWriter.
An object from class "Clients" is the shared memory between the threads serving the clients. It contains a private array list of the connected clients and the public methods to add, to remove and count the connected clients. It also includes a method to iterate over and send a message to each item in the list.
The threads serving the clients are implemented by the class ServeOneClient. The constructor creates IO streams on the corresponding socket, reads the name sent by the new client, adds the new client to the list of connected clients and starts the thread. The thread starts by printing information about the new client to the server console and sending this information to all connected clients. It then starts a loop listening to the client for a new message, which it forwards to all connected clients. After receiving a message to terminate the dialogue ("END"), it exits the loop, removes the client from the list of connected clients, closes the socket, and terminates the thread.
package chat_srv;
import java.io.*;
import java.net.*;
import java.util.*;
class Client{
String name;
PrintWriter pw;
Client(String name, PrintWriter p){
this.name = name;
this.pw =p;
}
}
class Clients{
private ArrayList<Client> cl;
public Clients(){
cl = new ArrayList<Client>(10);
}
public synchronized void addC(Client c){
cl.add(c);
}
public synchronized void rmvC(Client c){
cl.remove(c);
}
public synchronized void sendC(String s){
Iterator<Client> itr = cl.iterator();
while(itr.hasNext()) {
PrintWriter p=(PrintWriter)(itr.next().pw);
p.println(s);
}
}
public synchronized int nCl(){
return cl.size();
}
}
//...............................................................
class ServeOneClient extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private Client cl;
Clients clt;
public ServeOneClient(Socket s,Clients clt) throws IOException {
socket = s;
this.clt =clt;
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
// Enable auto-flush:
out = new PrintWriter( new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream()
)
),
true);
// If any of the above calls throw an
// exception, the caller is responsible for
// closing the socket. Otherwise the thread
// will close it.
String name = in.readLine(); // reading the client name
clt.addC(cl=new Client(name,out));
start(); // Calls run()
}
public void run() {
System.out.println("join a new client "+ cl.name+ " - total number "+ clt.nCl());
clt.sendC(" join a new client "+ cl.name + ". Total number clients "+clt.nCl()); //informing the clients for new participant
try {
while (true) {
String str = in.readLine();
if (str.equals("END")) break;
System.out.println(str);
clt.sendC(str);
}
} catch (IOException e) { }
finally {
try {
clt.rmvC(cl);
System.out.println("disconect client "+cl.name + ". Total number "+clt.nCl());
clt.sendC("disconecting client "+ cl.name + ". Total number clients connected "+clt.nCl());
socket.close();
} catch(IOException e) {}
}
}
}
//................................................................................
public class ChatSrv {
static final int PORT = 9393; //server port
public static void main(String[] args) throws IOException {
ServerSocket s = null;
try{
s = new ServerSocket(PORT);
}
catch(java.net.BindException be) {
System.out.println("There is another server running on this port");
System.exit(1);
}
System.out.println("Server Started");
Clients clt = new Clients();
try {
while(true) {
// Blocks until a connection occurs:
Socket socket = s.accept();
try {
new ServeOneClient(socket,clt);
} catch(IOException e) {
// If it fails, close the socket,
// otherwise the thread will close it:
socket.close();
}
}
} finally {
s.close();
}
}
}