Skip to content
7 changes: 0 additions & 7 deletions src/chat/Client.java

This file was deleted.

7 changes: 0 additions & 7 deletions src/chat/Server.java

This file was deleted.

76 changes: 76 additions & 0 deletions src/chat/clientside/Client.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package chat.clientside;

import chat.common.Commands;
import chat.common.Configs;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Client {
private static final Logger LOGGER = Logger.getLogger(Client.class.getName());

private final String name;

public Client(String name) {
this.name = name;
}

public void start() {
final Scanner scanner = new Scanner(System.in);

try (final Socket socket = new Socket(InetAddress.getByName(Configs.CHAT_SERVER_ADDRESS), Configs.CHAT_SERVER_PORT)) {
LOGGER.info(String.format("Established connection to %s", socket.getRemoteSocketAddress().toString()));

final DataOutputStream output = new DataOutputStream(socket.getOutputStream());
final DataInputStream input = new DataInputStream(socket.getInputStream());

final Thread receivedMessagesHandler = new Thread(() -> {
try {
while (true) {
final String msg = input.readUTF();
final LocalDateTime now = LocalDateTime.now().withNano(0);
System.out.println(String.format("[%s] %s", now.toString().replace('T', ' '), msg));
}
} catch(IOException e){
LOGGER.log(Level.SEVERE, "Cannot interact with the server");
}
});

receivedMessagesHandler.start();

output.writeUTF(name);

while (true) {
final String msgToSend = scanner.nextLine();
output.writeUTF(msgToSend);

if (msgToSend.trim().equalsIgnoreCase(Commands.EXIT.getCode())) {
break;
}
}

socket.close();
input.close();
output.close();
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Cannot interact with the server", e);
}
}

public static void main(String[] args) {
if (args.length < 1) {
System.out.println("Please, specify your name as an argument when starting it.");
return;
}

Client client = new Client(args[0]);
client.start();
}
}
16 changes: 16 additions & 0 deletions src/chat/common/Commands.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package chat.common;

public enum Commands {

EXIT("/exit"), LIST("/list");

Commands(String code) {
this.code = code;
}

private final String code;

public String getCode() {
return code;
}
}
10 changes: 10 additions & 0 deletions src/chat/common/Configs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package chat.common;

public final class Configs {

private Configs() { }

public static final int CHAT_SERVER_PORT = 23456;
public static final String CHAT_SERVER_ADDRESS = "127.0.0.1";
public static final int THREAD_POOL_SIZE = 1;
}
86 changes: 86 additions & 0 deletions src/chat/serverside/ClientHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package chat.serverside;

import chat.common.Commands;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ClientHandler extends Thread {
private static final Logger LOGGER = Logger.getLogger(ClientHandler.class.getName());

private final Server server;
private final Socket clientSocket;

private final DataInputStream input;
private final DataOutputStream output;

private final UUID clientId;
private String clientName = "Unknown";

public ClientHandler(UUID clientId, Server server, Socket client) throws IOException {
this.clientId = clientId;
this.server = server;
this.clientSocket = client;
this.input = new DataInputStream(client.getInputStream());
this.output = new DataOutputStream(client.getOutputStream());
}

public void sendMsg(String msg) throws IOException {
output.writeUTF(msg);
output.flush();
}

@Override
public void run() {
try {
this.clientName = input.readUTF();

final String helloMsg = String.format("%s is ready to start chatting\n", clientName);
server.broadcastMessage(helloMsg);

while (true) {
if (clientSocket.isClosed()) {
break;
}

final String msg = input.readUTF();
if (msg.trim().equalsIgnoreCase(Commands.EXIT.getCode())) {
disconnect();
break;
}

final String msgWithClient = clientName + ": " + msg;
LOGGER.info(msgWithClient);
server.broadcastMessage(msgWithClient);
}
} catch(IOException e){
LOGGER.log(Level.SEVERE, String.format("Cannot interact with %s", clientName), e);
disconnect();
}
}

private void disconnect() {
try {
clientSocket.close();
input.close();
output.close();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, String.format("Cannot disconnect %s", clientName), e);
}
server.dropClient(clientId);
server.broadcastMessage(String.format("%s disconnected from the server\n", clientName));
}

public String getClientName() {
return clientName;
}

public UUID getClientId() {
return clientId;
}
}
68 changes: 68 additions & 0 deletions src/chat/serverside/Server.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package chat.serverside;

import chat.common.Configs;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Server {
private static final Logger LOGGER = Logger.getLogger(Server.class.getName());

private static ArrayList<ClientHandler> handlers = new ArrayList<>();

private final int port;

public Server(int port) {
this.port = port;
}

public void start() {
try (final ServerSocket server = new ServerSocket(port)) {
LOGGER.info(String.format("The chat server has been started on port %d", server.getLocalPort()));
while (true) {
LOGGER.info("Waiting for a client");
final Socket client = server.accept();
regNewClient(client);
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, String.format("Cannot start server on %d", Configs.CHAT_SERVER_PORT), e);
}
}

public synchronized void regNewClient(Socket client) {
try {
final ClientHandler clientThread = new ClientHandler(UUID.randomUUID(), this, client);
clientThread.start();
handlers.add(clientThread);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Cannot register a new client", e);
}
}

public synchronized void dropClient(UUID clientId) {
handlers.removeIf(client -> Objects.equals(client.getClientId(), clientId));
}

public synchronized void broadcastMessage(String msg) {
handlers.forEach(handler -> {
try {
handler.sendMsg(msg);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, String.format("Cannot send message to %s", handler.getClientName()), e);
}
});
}

public static void main(String[] args) {
final Server chatServer = new Server(Configs.CHAT_SERVER_PORT);
chatServer.start();
}
}