Simple Chat Application in Java

Console-Based Chat Application

Basic Console Chat

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
public class SimpleConsoleChat {
private static final int PORT = 8080;
private static Set<PrintWriter> clientWriters = new CopyOnWriteArraySet<>();
private static Set<String> clientNames = new ConcurrentHashMap().newKeySet();
public static void main(String[] args) {
System.out.println("Simple Chat Application");
System.out.println("1. Start Server");
System.out.println("2. Start Client");
System.out.print("Choose option: ");
Scanner scanner = new Scanner(System.in);
String choice = scanner.nextLine();
if (choice.equals("1")) {
startServer();
} else if (choice.equals("2")) {
startClient();
} else {
System.out.println("Invalid option");
}
}
// Server Implementation
public static void startServer() {
System.out.println("Starting Chat Server on port " + PORT);
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
while (true) {
new ClientHandler(serverSocket.accept()).start();
}
} catch (IOException e) {
System.err.println("Server error: " + e.getMessage());
}
}
// Client Implementation
public static void startClient() {
System.out.print("Enter your username: ");
Scanner scanner = new Scanner(System.in);
String username = scanner.nextLine();
try (Socket socket = new Socket("localhost", PORT);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {
// Send username to server
out.println(username);
// Start thread for reading messages from server
Thread readerThread = new Thread(() -> {
try {
String serverMessage;
while ((serverMessage = in.readLine()) != null) {
System.out.println(serverMessage);
}
} catch (IOException e) {
System.out.println("Disconnected from server");
}
});
readerThread.start();
// Read user input and send to server
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
if ("/quit".equalsIgnoreCase(userInput)) {
break;
}
}
} catch (UnknownHostException e) {
System.err.println("Unknown host: localhost");
} catch (IOException e) {
System.err.println("Couldn't connect to server: " + e.getMessage());
}
}
// Client Handler for Server
private static class ClientHandler extends Thread {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
private String clientName;
public ClientHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// Get client name
clientName = in.readLine();
if (clientName == null) return;
clientNames.add(clientName);
clientWriters.add(out);
System.out.println(clientName + " joined the chat");
broadcastMessage("SERVER: " + clientName + " joined the chat", null);
String message;
while ((message = in.readLine()) != null) {
if ("/quit".equalsIgnoreCase(message)) {
break;
} else if ("/users".equalsIgnoreCase(message)) {
out.println("Online users: " + String.join(", ", clientNames));
} else if (message.startsWith("/whisper ")) {
handleWhisper(message);
} else {
broadcastMessage(clientName + ": " + message, out);
}
}
} catch (IOException e) {
System.out.println("Client disconnected: " + e.getMessage());
} finally {
cleanup();
}
}
private void handleWhisper(String message) {
try {
String[] parts = message.split(" ", 3);
if (parts.length >= 3) {
String targetUser = parts[1];
String whisperMessage = parts[2];
// Find target user and send whisper
for (PrintWriter writer : clientWriters) {
if (writer != out) { // Don't send to self
// In a real implementation, you'd need to track which writer belongs to which user
writer.println("[WHISPER from " + clientName + "]: " + whisperMessage);
}
}
}
} catch (Exception e) {
out.println("Invalid whisper format. Use: /whisper username message");
}
}
private void cleanup() {
if (clientName != null) {
clientNames.remove(clientName);
System.out.println(clientName + " left the chat");
broadcastMessage("SERVER: " + clientName + " left the chat", null);
}
if (out != null) {
clientWriters.remove(out);
}
try {
socket.close();
} catch (IOException e) {
// Ignore
}
}
}
private static void broadcastMessage(String message, PrintWriter excludeWriter) {
for (PrintWriter writer : clientWriters) {
if (writer != excludeWriter) {
writer.println(message);
}
}
}
}

GUI Chat Application with Swing

Chat Client GUI

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class ChatClientGUI {
private JFrame frame;
private JTextArea chatArea;
private JTextField messageField;
private JButton sendButton;
private JList<String> userList;
private DefaultListModel<String> userListModel;
private PrintWriter out;
private BufferedReader in;
private String username;
private Socket socket;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new ChatClientGUI().createAndShowGUI();
});
}
public void createAndShowGUI() {
// Login dialog
username = JOptionPane.showInputDialog(frame, "Enter your username:", "Chat Login", JOptionPane.PLAIN_MESSAGE);
if (username == null || username.trim().isEmpty()) {
System.exit(0);
}
username = username.trim();
// Create main frame
frame = new JFrame("Chat Client - " + username);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
// Chat area
chatArea = new JTextArea(20, 40);
chatArea.setEditable(false);
chatArea.setLineWrap(true);
chatArea.setWrapStyleWord(true);
JScrollPane chatScrollPane = new JScrollPane(chatArea);
frame.add(chatScrollPane, BorderLayout.CENTER);
// User list
userListModel = new DefaultListModel<>();
userList = new JList<>(userListModel);
userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane userScrollPane = new JScrollPane(userList);
userScrollPane.setPreferredSize(new Dimension(150, 0));
frame.add(userScrollPane, BorderLayout.EAST);
// Input panel
JPanel inputPanel = new JPanel(new BorderLayout());
messageField = new JTextField();
sendButton = new JButton("Send");
inputPanel.add(messageField, BorderLayout.CENTER);
inputPanel.add(sendButton, BorderLayout.EAST);
frame.add(inputPanel, BorderLayout.SOUTH);
// Event handlers
sendButton.addActionListener(e -> sendMessage());
messageField.addActionListener(e -> sendMessage());
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
disconnect();
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// Connect to server
connectToServer();
}
private void connectToServer() {
try {
socket = new Socket("localhost", 8080);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Send username to server
out.println(username);
// Start thread to read messages from server
new Thread(this::readMessages).start();
appendToChat("Connected to chat server as " + username);
} catch (IOException e) {
JOptionPane.showMessageDialog(frame, "Could not connect to server: " + e.getMessage(), 
"Connection Error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
private void readMessages() {
try {
String message;
while ((message = in.readLine()) != null) {
if (message.startsWith("USERLIST:")) {
updateUserList(message.substring(9));
} else {
appendToChat(message);
}
}
} catch (IOException e) {
appendToChat("Disconnected from server");
}
}
private void sendMessage() {
String message = messageField.getText().trim();
if (!message.isEmpty()) {
out.println(message);
messageField.setText("");
if ("/quit".equalsIgnoreCase(message)) {
disconnect();
}
}
}
private void appendToChat(String message) {
SwingUtilities.invokeLater(() -> {
chatArea.append(message + "\n");
chatArea.setCaretPosition(chatArea.getDocument().getLength());
});
}
private void updateUserList(String userListString) {
SwingUtilities.invokeLater(() -> {
userListModel.clear();
String[] users = userListString.split(",");
for (String user : users) {
if (!user.trim().isEmpty()) {
userListModel.addElement(user.trim());
}
}
});
}
private void disconnect() {
try {
if (out != null) {
out.println("/quit");
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
// Ignore
}
System.exit(0);
}
}

Enhanced Chat Server

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
public class EnhancedChatServer {
private static final int PORT = 8080;
private static Set<ClientHandler> clients = ConcurrentHashMap.newKeySet();
private static Map<String, ClientHandler> clientMap = new ConcurrentHashMap<>();
public static void main(String[] args) {
System.out.println("Enhanced Chat Server starting on port " + PORT);
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
while (true) {
new ClientHandler(serverSocket.accept()).start();
}
} catch (IOException e) {
System.err.println("Server error: " + e.getMessage());
}
}
public static void broadcastMessage(String message, ClientHandler excludeClient) {
for (ClientHandler client : clients) {
if (client != excludeClient) {
client.sendMessage(message);
}
}
}
public static void updateUserList() {
String userList = "USERLIST:" + String.join(",", clientMap.keySet());
for (ClientHandler client : clients) {
client.sendMessage(userList);
}
}
public static void sendPrivateMessage(String fromUser, String toUser, String message) {
ClientHandler targetClient = clientMap.get(toUser);
if (targetClient != null) {
targetClient.sendMessage("[Private from " + fromUser + "]: " + message);
} else {
ClientHandler senderClient = clientMap.get(fromUser);
if (senderClient != null) {
senderClient.sendMessage("User " + toUser + " is not online");
}
}
}
// Client Handler class
private static class ClientHandler extends Thread {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
private String username;
public ClientHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// Authentication
username = in.readLine();
if (username == null || username.trim().isEmpty() || clientMap.containsKey(username)) {
out.println("ERROR: Invalid username or username already taken");
return;
}
username = username.trim();
// Register client
clients.add(this);
clientMap.put(username, this);
System.out.println(username + " connected from " + socket.getInetAddress());
broadcastMessage("SERVER: " + username + " joined the chat", this);
updateUserList();
// Handle messages
String message;
while ((message = in.readLine()) != null) {
if ("/quit".equalsIgnoreCase(message)) {
break;
} else if (message.startsWith("/whisper ")) {
handleWhisper(message);
} else if (message.startsWith("/msg ")) {
handlePrivateMessage(message);
} else if ("/users".equalsIgnoreCase(message)) {
sendMessage("Online users: " + String.join(", ", clientMap.keySet()));
} else if (message.startsWith("/kick ") && username.equals("admin")) {
handleKickCommand(message);
} else {
broadcastMessage(username + ": " + message, this);
}
}
} catch (IOException e) {
System.out.println("Client error: " + e.getMessage());
} finally {
disconnect();
}
}
private void handleWhisper(String message) {
try {
String[] parts = message.split(" ", 3);
if (parts.length >= 3) {
String targetUser = parts[1];
String whisperMessage = parts[2];
sendPrivateMessage(username, targetUser, whisperMessage);
}
} catch (Exception e) {
sendMessage("Invalid whisper format. Use: /whisper username message");
}
}
private void handlePrivateMessage(String message) {
try {
String[] parts = message.split(" ", 3);
if (parts.length >= 3) {
String targetUser = parts[1];
String privateMessage = parts[2];
sendPrivateMessage(username, targetUser, privateMessage);
sendMessage("[Private to " + targetUser + "]: " + privateMessage);
}
} catch (Exception e) {
sendMessage("Invalid private message format. Use: /msg username message");
}
}
private void handleKickCommand(String message) {
try {
String[] parts = message.split(" ");
if (parts.length >= 2) {
String targetUser = parts[1];
ClientHandler targetClient = clientMap.get(targetUser);
if (targetClient != null) {
targetClient.sendMessage("You have been kicked by admin");
targetClient.disconnect();
broadcastMessage("SERVER: " + targetUser + " was kicked by admin", null);
}
}
} catch (Exception e) {
sendMessage("Invalid kick command format. Use: /kick username");
}
}
public void sendMessage(String message) {
out.println(message);
}
private void disconnect() {
if (username != null) {
clients.remove(this);
clientMap.remove(username);
System.out.println(username + " disconnected");
broadcastMessage("SERVER: " + username + " left the chat", null);
updateUserList();
}
try {
socket.close();
} catch (IOException e) {
// Ignore
}
}
}
}

WebSocket Chat Application

WebSocket Server (Using Java-WebSocket library)

First, add this dependency to your pom.xml:

<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.3</version>
</dependency>
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class WebSocketChatServer extends WebSocketServer {
private Map<WebSocket, String> clientUsernames = new ConcurrentHashMap<>();
private Set<WebSocket> clients = ConcurrentHashMap.newKeySet();
public WebSocketChatServer(int port) {
super(new InetSocketAddress(port));
}
@Override
public void onStart() {
System.out.println("WebSocket Chat Server started on port: " + getPort());
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
clients.add(conn);
System.out.println("New connection from: " + conn.getRemoteSocketAddress());
conn.send("Welcome to WebSocket Chat! Please send your username.");
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
String username = clientUsernames.get(conn);
clients.remove(conn);
clientUsernames.remove(conn);
if (username != null) {
broadcast("SERVER: " + username + " left the chat", conn);
System.out.println(username + " disconnected");
}
}
@Override
public void onMessage(WebSocket conn, String message) {
String username = clientUsernames.get(conn);
if (username == null) {
// First message is username
if (isValidUsername(message)) {
clientUsernames.put(conn, message);
conn.send("Username set to: " + message);
broadcast("SERVER: " + message + " joined the chat", conn);
System.out.println("User registered: " + message);
} else {
conn.send("Invalid username. Please choose another one.");
}
} else {
// Regular chat message
if (message.startsWith("/")) {
handleCommand(conn, message);
} else {
broadcast(username + ": " + message, conn);
}
}
}
@Override
public void onError(WebSocket conn, Exception ex) {
System.err.println("WebSocket error: " + ex.getMessage());
if (conn != null) {
clients.remove(conn);
clientUsernames.remove(conn);
}
}
private boolean isValidUsername(String username) {
return username != null && 
!username.trim().isEmpty() && 
!clientUsernames.containsValue(username) &&
username.length() <= 20;
}
private void handleCommand(WebSocket conn, String message) {
String username = clientUsernames.get(conn);
if (message.equals("/users")) {
String userList = "Online users: " + String.join(", ", clientUsernames.values());
conn.send(userList);
} else if (message.startsWith("/whisper ")) {
String[] parts = message.split(" ", 3);
if (parts.length == 3) {
String targetUser = parts[1];
String whisperMessage = parts[2];
for (Map.Entry<WebSocket, String> entry : clientUsernames.entrySet()) {
if (entry.getValue().equals(targetUser)) {
entry.getKey().send("[Whisper from " + username + "]: " + whisperMessage);
conn.send("[Whisper to " + targetUser + "]: " + whisperMessage);
return;
}
}
conn.send("User " + targetUser + " not found");
}
} else {
conn.send("Unknown command: " + message);
}
}
private void broadcast(String message, WebSocket exclude) {
for (WebSocket client : clients) {
if (client != exclude && client.isOpen()) {
client.send(message);
}
}
}
public static void main(String[] args) {
int port = 8887;
WebSocketChatServer server = new WebSocketChatServer(port);
server.start();
System.out.println("WebSocket Chat Server running on ws://localhost:" + port);
}
}

Simple Chat Features

Chat Room Manager

import java.util.*;
import java.util.concurrent.*;
public class ChatRoomManager {
private Map<String, ChatRoom> chatRooms = new ConcurrentHashMap<>();
public ChatRoomManager() {
// Create default room
createRoom("general");
}
public ChatRoom createRoom(String roomName) {
ChatRoom room = new ChatRoom(roomName);
chatRooms.put(roomName, room);
return room;
}
public ChatRoom getRoom(String roomName) {
return chatRooms.get(roomName);
}
public List<String> getRoomList() {
return new ArrayList<>(chatRooms.keySet());
}
public boolean joinRoom(String roomName, ChatClient client) {
ChatRoom room = chatRooms.get(roomName);
if (room != null) {
room.addClient(client);
return true;
}
return false;
}
public void leaveRoom(String roomName, ChatClient client) {
ChatRoom room = chatRooms.get(roomName);
if (room != null) {
room.removeClient(client);
}
}
}
class ChatRoom {
private String name;
private Set<ChatClient> clients = ConcurrentHashMap.newKeySet();
public ChatRoom(String name) {
this.name = name;
}
public void addClient(ChatClient client) {
clients.add(client);
broadcast("SERVER: " + client.getUsername() + " joined " + name, null);
}
public void removeClient(ChatClient client) {
clients.remove(client);
broadcast("SERVER: " + client.getUsername() + " left " + name, null);
}
public void broadcast(String message, ChatClient exclude) {
for (ChatClient client : clients) {
if (client != exclude) {
client.sendMessage(message);
}
}
}
public String getName() { return name; }
public Set<ChatClient> getClients() { return clients; }
}
interface ChatClient {
String getUsername();
void sendMessage(String message);
}

Message Format and History

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class ChatMessage {
private String username;
private String message;
private LocalDateTime timestamp;
private MessageType type;
public enum MessageType {
TEXT, JOIN, LEAVE, WHISPER, SYSTEM
}
public ChatMessage(String username, String message, MessageType type) {
this.username = username;
this.message = message;
this.type = type;
this.timestamp = LocalDateTime.now();
}
public String toFormattedString() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
String time = timestamp.format(formatter);
switch (type) {
case JOIN:
return "[" + time + "] " + username + " joined the chat";
case LEAVE:
return "[" + time + "] " + username + " left the chat";
case WHISPER:
return "[" + time + "] [Whisper] " + username + ": " + message;
case SYSTEM:
return "[" + time + "] [System] " + message;
default:
return "[" + time + "] " + username + ": " + message;
}
}
// Getters
public String getUsername() { return username; }
public String getMessage() { return message; }
public LocalDateTime getTimestamp() { return timestamp; }
public MessageType getType() { return type; }
}
class MessageHistory {
private List<ChatMessage> messages = Collections.synchronizedList(new ArrayList<>());
private static final int MAX_HISTORY = 1000;
public void addMessage(ChatMessage message) {
messages.add(message);
// Keep only recent messages
if (messages.size() > MAX_HISTORY) {
messages.remove(0);
}
}
public List<ChatMessage> getRecentMessages(int count) {
int start = Math.max(0, messages.size() - count);
return new ArrayList<>(messages.subList(start, messages.size()));
}
public void clear() {
messages.clear();
}
}

Running the Chat Application

How to Run:

  1. Console Version:
  • Compile all Java files
  • Run java SimpleConsoleChat
  • Choose option 1 to start server
  • Open new terminals and choose option 2 to start clients
  1. GUI Version:
  • Start the EnhancedChatServer first
  • Run ChatClientGUI for each client
  • Enter username when prompted
  1. WebSocket Version:
  • Add the Java-WebSocket dependency
  • Run WebSocketChatServer
  • Use a WebSocket client or browser to connect

Features Included:

  • Multiple clients can connect simultaneously
  • Real-time messaging between clients
  • User list showing online users
  • Private messaging (/whisper command)
  • User commands (/users, /quit)
  • Basic admin features (kick users)
  • GUI interface with Swing
  • WebSocket support for web clients

This simple chat application demonstrates core networking concepts in Java and can be extended with features like user authentication, message persistence, file sharing, or voice/video chat.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper