From daa945198435d5e1253914dfaac407ace14925bd Mon Sep 17 00:00:00 2001 From: Mobina Date: Sat, 20 Jun 2026 00:15:44 +0330 Subject: [PATCH 1/2] develop --- .../chat/Client/ServerListener.java | 36 ++++++- .../university/chat/Client/chatClient.java | 37 ++++++- .../university/chat/Server/ChatServer.java | 29 +++++- .../university/chat/Server/ClientSession.java | 99 ++++++++++++++++++- 4 files changed, 193 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/university/chat/Client/ServerListener.java b/src/main/java/com/university/chat/Client/ServerListener.java index b609d74..a747fe3 100644 --- a/src/main/java/com/university/chat/Client/ServerListener.java +++ b/src/main/java/com/university/chat/Client/ServerListener.java @@ -1,18 +1,44 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Common.FileMessage; + +import java.io.ObjectInputStream; + public class ServerListener implements Runnable{ // TODO: store the ObjectInputStream from the user socket // (this should be the same input stream the // chatClient created when connecting) + private final ObjectInputStream in; + + public ServerListener(ObjectInputStream in){ + this.in = in; + } + @Override public void run() { try { - // TODO: In an infinite loop read objects from the server - // - if it's a ChatMessage -> print ": " - // - if it's a FileMessage -> print that a file was received - // (filename + sender), it's already - // saved to disk by the server. + while(true){ + Object obj = in.readObject(); + + if(obj instanceof ChatMessage msg){ + System.out.println( + msg.getSender() + + ": " + + msg.getContent() + ); + } + + else if(obj instanceof FileMessage file){ + System.out.println( + "File received from " + + file.getSender() + + ": " + + file.getFilename() + ); + } + } } catch (Exception e){ System.out.println("Disconnected from server"); } diff --git a/src/main/java/com/university/chat/Client/chatClient.java b/src/main/java/com/university/chat/Client/chatClient.java index dae0bad..ec38c2d 100644 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ b/src/main/java/com/university/chat/Client/chatClient.java @@ -1,6 +1,20 @@ package com.university.chat.Client; +import com.university.chat.Common.ChatMessage; +import com.university.chat.Server.ClientSession; +import com.university.chat.Server.UserManager; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Scanner; + public class chatClient { + public static final UserManager userManager = + new UserManager(); + public static void main() { // TODO: Connecting to the server // 1. Create a socket and connect to the server @@ -9,11 +23,20 @@ public class chatClient { // 2. Get the username, and send a LOGIN ChatMessage with that username // 3. Start a new Thread running a ServerListener(in) so incoming // messages are handled concurrently. + ServerSocket serverSocket; + + try{ + serverSocket =new ServerSocket(5000); + + System.out.println("Server started"); + } catch (Exception e) { + throw new RuntimeException(e); + } while (true){ try { // TODO: Program loop — read a line from the console and act on it: - // - "/msg " -> build & send a PRIVATE_MESSAGE + // - "/msg " -> build & send a PRIVATE_MESSAGE // - "/users" -> build & send a USER_LIST request // - "/sendfile " -> read the file into a byte[] // (you can use TransferProgress @@ -21,6 +44,18 @@ public class chatClient { // and send it as a FileMessage // - anything else -> send a PUBLIC_MESSAGE // Remember to flush() the output stream after writeObject(). + + Socket socket = + serverSocket.accept(); + + ClientSession session = + new ClientSession( + socket, + userManager + ); + + new Thread(session).start(); + } catch (Exception e){ System.out.println("command failed: " + e.getMessage()); } diff --git a/src/main/java/com/university/chat/Server/ChatServer.java b/src/main/java/com/university/chat/Server/ChatServer.java index b2a35ae..98f1c6a 100644 --- a/src/main/java/com/university/chat/Server/ChatServer.java +++ b/src/main/java/com/university/chat/Server/ChatServer.java @@ -1,15 +1,42 @@ package com.university.chat.Server; +import java.net.ServerSocket; +import java.net.Socket; + public class ChatServer { // TODO: declare a single shared UserManager instance (static final) // This MUST be shared by all ClientSession threads so that // broadcasting and private messaging work correctly. + private static final UserManager userManager = + new UserManager(); public static void main(String[] args) { // TODO: Create a ServerSocket + try (ServerSocket serverSocket = + new ServerSocket(5000)) { + System.out.println("Server started"); + + while (true) { + + Socket socket = + serverSocket.accept(); + + ClientSession session = + new ClientSession( + socket, + userManager + ); + + new Thread(session).start(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } // TODO: In an infinite loop: // accept an incoming client connection // make a new thread running ClientSession for each user. - } + } diff --git a/src/main/java/com/university/chat/Server/ClientSession.java b/src/main/java/com/university/chat/Server/ClientSession.java index f09d64a..6ff38d3 100644 --- a/src/main/java/com/university/chat/Server/ClientSession.java +++ b/src/main/java/com/university/chat/Server/ClientSession.java @@ -2,18 +2,38 @@ package com.university.chat.Server; import com.university.chat.Common.ChatMessage; import com.university.chat.Common.FileMessage; +import com.university.chat.Common.MessageType; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.net.Socket; import java.nio.file.Files; +import static com.university.chat.Client.chatClient.userManager; + public class ClientSession implements Runnable { private String username; + private final Socket socket; + private final UserManager userManager; + + private ObjectInputStream in; + private ObjectOutputStream out; public ClientSession(Socket socket, UserManager userManager) { // TODO : Create an ObjectOutputStream from socket.getOutputStream() // and an ObjectInputStream from socket.getInputStream(). + this.socket=socket; + this.userManager=userManager; + try { + out = new ObjectOutputStream(socket.getOutputStream()); + out.flush(); + + in = new ObjectInputStream(socket.getInputStream()); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override @@ -28,18 +48,65 @@ public class ClientSession implements Runnable { // 5. If the username is taken, send back LOGIN_FAILED and close the socket. // 6. Otherwise, create the user's folders with FileManager.createUserFolders(...) // and send back LOGIN_SUCCESS. + Object first = in.readObject(); + if (!(first instanceof ChatMessage msg) + || msg.getType() != MessageType.LOGIN) { + + socket.close(); + return; + } + username = msg.getSender(); + if (!userManager.addUser(username, this)) { + + send(new ChatMessage( + MessageType.LOGIN_FAILED, + "SERVER", + username, + "Username already exists" + )); + + socket.close(); + return; + } + FileManager.createUserFolders(username); + + send(new ChatMessage( + MessageType.LOGIN_SUCCESS, + "SERVER", + username, + "Login successful" + )); // TODO: Main message loop // In a loop, call in.readObject(), you can separate messages by their type: // - if it's a ChatMessage -> call handleChatMessage(msg) // - if it's a FileMessage -> call handleFileMessage(fileMsg) // Keep looping until the connection is closed (an exception will be thrown). + while(true){ + + Object obj = in.readObject(); + + if(obj instanceof ChatMessage mesg){ + handleChatMessage(mesg); + } + + else if(obj instanceof FileMessage file){ + handleFileMessage(file); + } + } } catch (Exception e) { System.out.println("Disconnected: " + username); } finally { // TODO: Remove the user from UserManager so they no longer // receive broadcasts or appear in users list + if(username != null){ + userManager.removeUser(username); + } + try { + socket.close(); + } catch (IOException ignored) { + } } } @@ -48,12 +115,27 @@ public class ClientSession implements Runnable { switch (msg.getType()) { case PUBLIC_MESSAGE -> { // TODO: Broadcast this message to every connected client. + for(ClientSession session : + userManager.getAllSessions()){ + session.send(msg); + } } case PRIVATE_MESSAGE -> { - // TODO: Forward this message to the receiver user. + ClientSession target = + userManager.getUser(msg.getReceiver()); + + if(target != null){ + target.send(msg); + } } case USER_LIST -> { // TODO: Reply to the requester with the list of online users. + send(new ChatMessage( + MessageType.USER_LIST, + "SERVER", + username, + userManager.listUsers() + )); } } } @@ -67,5 +149,20 @@ public class ClientSession implements Runnable { Files.write(recvPath, fileMsg.getData()); // TODO: Forward the received file-message to the destination user. + ClientSession target = + userManager.getUser( + fileMsg.getReceiver() + ); + + if(target != null){ + target.send(fileMsg); + } + } + + public synchronized void send(Object obj) + throws IOException { + + out.writeObject(obj); + out.flush(); } } \ No newline at end of file -- 2.54.0 From 075c02fefe00f594efaa4cfc36a5765f7f8b1c53 Mon Sep 17 00:00:00 2001 From: Mobina Date: Sat, 18 Jul 2026 00:04:31 +0330 Subject: [PATCH 2/2] correcting chatClient --- .../university/chat/Client/chatClient.java | 155 +++++++++++++----- .../university/chat/Server/ClientSession.java | 1 - 2 files changed, 113 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/university/chat/Client/chatClient.java b/src/main/java/com/university/chat/Client/chatClient.java index ec38c2d..7daecff 100644 --- a/src/main/java/com/university/chat/Client/chatClient.java +++ b/src/main/java/com/university/chat/Client/chatClient.java @@ -1,64 +1,135 @@ package com.university.chat.Client; import com.university.chat.Common.ChatMessage; -import com.university.chat.Server.ClientSession; -import com.university.chat.Server.UserManager; +import com.university.chat.Common.FileMessage; +import com.university.chat.Common.MessageType; -import java.io.IOException; +import java.io.File; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.net.ServerSocket; import java.net.Socket; +import java.nio.file.Files; import java.util.Scanner; public class chatClient { - public static final UserManager userManager = - new UserManager(); - public static void main() { - // TODO: Connecting to the server - // 1. Create a socket and connect to the server - // 2. Create an ObjectOutputStream (out) and ObjectInputStream (in) - // from the socket's streams — output FIRST, then input. - // 2. Get the username, and send a LOGIN ChatMessage with that username - // 3. Start a new Thread running a ServerListener(in) so incoming - // messages are handled concurrently. - ServerSocket serverSocket; + public static void main(String[] args) { - try{ - serverSocket =new ServerSocket(5000); + try { + Socket socket = new Socket("localhost", 8080); - System.out.println("Server started"); - } catch (Exception e) { - throw new RuntimeException(e); - } + ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); - while (true){ - try { - // TODO: Program loop — read a line from the console and act on it: - // - "/msg " -> build & send a PRIVATE_MESSAGE - // - "/users" -> build & send a USER_LIST request - // - "/sendfile " -> read the file into a byte[] - // (you can use TransferProgress - // to show progress) - // and send it as a FileMessage - // - anything else -> send a PUBLIC_MESSAGE - // Remember to flush() the output stream after writeObject(). + ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); - Socket socket = - serverSocket.accept(); + Scanner scanner = new Scanner(System.in); - ClientSession session = - new ClientSession( - socket, - userManager + System.out.print("Enter username: "); + String username = scanner.nextLine(); + + ChatMessage login = new ChatMessage( + MessageType.LOGIN, + username, + "", + "" + ); + + out.writeObject(login); + + new Thread(new ServerListener(in)).start(); + + while (true) { + + try { + + String text = scanner.nextLine(); + + if (text.startsWith("/msg ")) { + + String[] parts = text.split(" ", 3); + + if (parts.length < 3) { + System.out.println("Wrong command."); + continue; + } + + ChatMessage message = new ChatMessage( + MessageType.PRIVATE_MESSAGE, + username, + parts[1], + parts[2] ); - new Thread(session).start(); + out.writeObject(message); + out.flush(); + } + + else if (text.equals("/users")) { + + ChatMessage message = new ChatMessage( + MessageType.USER_LIST, + username, + "", + "" + ); + + out.writeObject(message); + out.flush(); + } + + else if (text.startsWith("/sendfile ")) { + + String[] parts = text.split(" ", 3); + + if (parts.length < 3) { + System.out.println("Wrong command."); + continue; + } + + File file = new File(parts[2]); + + if (!file.exists()) { + System.out.println("File not found."); + continue; + } + + byte[] data = Files.readAllBytes(file.toPath()); + + FileMessage fileMessage = new FileMessage( + username, + parts[1], + file.getName(), + data + ); + + out.writeObject(fileMessage); + out.flush(); + + System.out.println("File sent."); + } + + else { + + ChatMessage message = new ChatMessage( + MessageType.PUBLIC_MESSAGE, + username, + "", + text + ); + + out.writeObject(message); + out.flush(); + } + + } catch (Exception e) { + System.out.println("Command failed."); + } - } catch (Exception e){ - System.out.println("command failed: " + e.getMessage()); } + + } catch (Exception e) { } + } -} + +} \ No newline at end of file diff --git a/src/main/java/com/university/chat/Server/ClientSession.java b/src/main/java/com/university/chat/Server/ClientSession.java index 6ff38d3..5dcda44 100644 --- a/src/main/java/com/university/chat/Server/ClientSession.java +++ b/src/main/java/com/university/chat/Server/ClientSession.java @@ -10,7 +10,6 @@ import java.io.ObjectOutputStream; import java.net.Socket; import java.nio.file.Files; -import static com.university.chat.Client.chatClient.userManager; public class ClientSession implements Runnable { -- 2.54.0