From 255f9886d12c2043da59d874a783914de78b0798 Mon Sep 17 00:00:00 2001 From: MobinAbedian Date: Sun, 7 Jun 2026 10:23:19 +0330 Subject: [PATCH] init project --- pom.xml | 17 ++++++ src/main/java/chat/ChatClient.java | 72 +++++++++++++++++++++++ src/main/java/chat/ChatServer.java | 69 ++++++++++++++++++++++ src/main/java/chat/ClientHandler.java | 78 +++++++++++++++++++++++++ src/main/java/chat/MessageListener.java | 19 ++++++ 5 files changed, 255 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/chat/ChatClient.java create mode 100644 src/main/java/chat/ChatServer.java create mode 100644 src/main/java/chat/ClientHandler.java create mode 100644 src/main/java/chat/MessageListener.java diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cd4d8a5 --- /dev/null +++ b/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + org.example + chat-app + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + diff --git a/src/main/java/chat/ChatClient.java b/src/main/java/chat/ChatClient.java new file mode 100644 index 0000000..eb20460 --- /dev/null +++ b/src/main/java/chat/ChatClient.java @@ -0,0 +1,72 @@ +package chat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; + +public class ChatClient { + + private final String host; + private final int port; + private Socket socket; + private PrintWriter out; + private BufferedReader in; + private BufferedReader consoleReader; + + public ChatClient(String host, int port) { + this.host = host; + this.port = port; + this.consoleReader = new BufferedReader(new InputStreamReader(System.in)); + } + + public void start() { + try { + connectToServer(); + MessageListener messageListener = new MessageListener(in); + Thread listenerThread = new Thread(messageListener); + listenerThread.setDaemon(true); + listenerThread.start(); + readUserInputAndSend(); + } catch (IOException e) { + System.err.println("Client error: " + e.getMessage()); + } finally { + cleanup(); + } + } + + private void connectToServer() throws IOException { + // TODO: create socket connection to host:port + // TODO: initialize output stream (PrintWriter) + // TODO: initialize input stream (BufferedReader) + } + + private void readUserInputAndSend() throws IOException { + // TODO: read continuously from console + // TODO: send each input line to server + } + + private void cleanup() { + // TODO: close socket safely + // TODO: release resources + } + + public static void main(String[] args) { + String host = "127.0.0.1"; + int port = 12345; + + if (args.length > 0) { + host = args[0]; + } + if (args.length > 1) { + try { + port = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + System.err.println("Invalid port. Using default: " + port); + } + } + + new ChatClient(host, port).start(); + } +} diff --git a/src/main/java/chat/ChatServer.java b/src/main/java/chat/ChatServer.java new file mode 100644 index 0000000..218dbcd --- /dev/null +++ b/src/main/java/chat/ChatServer.java @@ -0,0 +1,69 @@ +package chat; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ChatServer { + + private final int port; + private final Set connectedClients; + private final ExecutorService threadPool; + + public ChatServer(int port) { + this.port = port; + this.connectedClients = Collections.synchronizedSet(new HashSet<>()); + this.threadPool = Executors.newCachedThreadPool(); + } + + public void start() { + try (ServerSocket serverSocket = new ServerSocket(port)) { + System.out.println("Chat server started on port " + port); + + while (true) { + Socket clientSocket = serverSocket.accept(); + ClientHandler clientHandler = new ClientHandler(clientSocket, this); + connectedClients.add(clientHandler); + threadPool.execute(clientHandler); + } + } catch (IOException e) { + System.err.println("Server error: " + e.getMessage()); + } finally { + threadPool.shutdown(); + } + } + + public void broadcast(String message, ClientHandler sender) { + // step 1: iterate through connectedClients safely + // step 2: skip the sender client + // step 3: send message to remaining clients using sendMessage + } + + public void broadcastSystemMessage(String message) { + // step 1: iterate through all connected clients + // step 2: send system message to each client + } + + public void removeClient(ClientHandler clientHandler) { + // step 1: remove client from connectedClients set + // step 2: retrieve username from clientHandler + // step 3: broadcast system message about user leaving + } + + public static void main(String[] args) { + int port = 12345; + if (args.length > 0) { + try { + port = Integer.parseInt(args[0]); + } catch (NumberFormatException e) { + System.err.println("Invalid port. Using default: " + port); + } + } + new ChatServer(port).start(); + } +} diff --git a/src/main/java/chat/ClientHandler.java b/src/main/java/chat/ClientHandler.java new file mode 100644 index 0000000..04484ba --- /dev/null +++ b/src/main/java/chat/ClientHandler.java @@ -0,0 +1,78 @@ +package chat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; + +public class ClientHandler implements Runnable { + + private final Socket clientSocket; + private final ChatServer chatServer; + private PrintWriter out; + private BufferedReader in; + private String username; + + public ClientHandler(Socket clientSocket, ChatServer chatServer) { + this.clientSocket = clientSocket; + this.chatServer = chatServer; + } + + @Override + public void run() { + try { + setupStreams(); + requestUsername(); + announceJoin(); + listenForMessages(); + } catch (IOException e) { + System.err.println("Client handler error: " + e.getMessage()); + } finally { + cleanup(); + } + } + + private void setupStreams() throws IOException { + out = new PrintWriter(clientSocket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + } + + private void requestUsername() throws IOException { + out.println("Enter your username:"); + username = in.readLine(); + if (username == null || username.trim().isEmpty()) { + username = "Anonymous"; + } + } + + private void announceJoin() { + chatServer.broadcastSystemMessage("[System] " + username + " joined the chat."); + } + + private void listenForMessages() throws IOException { + String message; + while ((message = in.readLine()) != null) { + chatServer.broadcast(username + ": " + message, this); + } + } + + private void cleanup() { + chatServer.removeClient(this); + try { + if (clientSocket != null && !clientSocket.isClosed()) { + clientSocket.close(); + } + } catch (IOException e) { + System.err.println("Error closing socket: " + e.getMessage()); + } + } + + public void sendMessage(String message) { + out.println(message); + } + + public String getUsername() { + return username; + } +} diff --git a/src/main/java/chat/MessageListener.java b/src/main/java/chat/MessageListener.java new file mode 100644 index 0000000..246256b --- /dev/null +++ b/src/main/java/chat/MessageListener.java @@ -0,0 +1,19 @@ +package chat; + +import java.io.BufferedReader; +import java.io.IOException; + +public class MessageListener implements Runnable { + + private final BufferedReader inputReader; + + public MessageListener(BufferedReader inputReader) { + this.inputReader = inputReader; + } + + @Override + public void run() { + // TODO: continuously read messages from server + // TODO: print received messages immediately + } +}