elikicker
2 years ago
11 changed files with 447 additions and 0 deletions
-
26crychat/client/Main.java
-
37crychat/client/log/EventLogger.java
-
54crychat/client/net/Client.java
-
18crychat/client/util/CeasarChipher.java
-
26crychat/server/Main.java
-
37crychat/server/log/EventLogger.java
-
68crychat/server/net/ChatClient.java
-
61crychat/server/net/ChatServer.java
-
18crychat/server/util/CeasarChipher.java
-
35crychat/server/util/Queue.java
-
67crychat/server/util/ServerBuilder.java
@ -0,0 +1,26 @@ |
|||||
|
package client; |
||||
|
|
||||
|
import client.log.EventLogger; |
||||
|
import client.net.Client; |
||||
|
|
||||
|
import java.io.BufferedReader; |
||||
|
import java.io.InputStreamReader; |
||||
|
|
||||
|
public class Main { |
||||
|
|
||||
|
public static EventLogger console; |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
System.out.println("Client!"); |
||||
|
console = new EventLogger(System.out); |
||||
|
Client c = new Client("localhost", 5001); |
||||
|
BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); |
||||
|
while (true) { |
||||
|
try { |
||||
|
c.write(r.readLine().getBytes()); |
||||
|
} catch (Throwable e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
package client.log; |
||||
|
|
||||
|
import java.io.PrintStream; |
||||
|
|
||||
|
public class EventLogger { |
||||
|
|
||||
|
private static final String ANSI_RESET = "\u001B[0m"; |
||||
|
private static final String ANSI_RED = "\u001B[31m"; |
||||
|
private static final String ANSI_GREEN = "\u001B[32m"; |
||||
|
private static final String ANSI_BLUE = "\u001B[34m"; |
||||
|
private static final String ANSI_WHITE = "\u001B[37m"; |
||||
|
private final PrintStream stream; |
||||
|
|
||||
|
public EventLogger(PrintStream stream) { |
||||
|
this.stream = stream; |
||||
|
} |
||||
|
|
||||
|
public void println(String msg) { |
||||
|
stream.println(msg); |
||||
|
} |
||||
|
|
||||
|
public void error(String msg) { |
||||
|
stream.println(ANSI_WHITE + "[" + ANSI_RED + "-" + ANSI_WHITE + "] " + msg + ANSI_RESET); |
||||
|
} |
||||
|
|
||||
|
public void info(String msg) { |
||||
|
stream.println(ANSI_WHITE + "[" + ANSI_BLUE + "*" + ANSI_WHITE + "] " + msg + ANSI_RESET); |
||||
|
} |
||||
|
|
||||
|
public void success(String msg) { |
||||
|
stream.println(ANSI_WHITE + "[" + ANSI_GREEN + "+" + ANSI_WHITE + "] " + msg + ANSI_RESET); |
||||
|
} |
||||
|
|
||||
|
public void close() { |
||||
|
stream.close(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
package client.net; |
||||
|
|
||||
|
import client.Main; |
||||
|
import client.util.CeasarChipher; |
||||
|
|
||||
|
import java.io.DataInputStream; |
||||
|
import java.io.DataOutputStream; |
||||
|
import java.io.IOException; |
||||
|
import java.net.Socket; |
||||
|
|
||||
|
public class Client { |
||||
|
|
||||
|
private Socket s; |
||||
|
private DataInputStream inputStream; |
||||
|
private DataOutputStream outputStream; |
||||
|
private Thread t; |
||||
|
|
||||
|
public Client(String host, int port) { |
||||
|
try { |
||||
|
s = new Socket(host, port); |
||||
|
inputStream = new DataInputStream(s.getInputStream()); |
||||
|
outputStream = new DataOutputStream(s.getOutputStream()); |
||||
|
t = new Thread(() -> { |
||||
|
try { |
||||
|
while (true) { |
||||
|
int len = inputStream.readInt(); |
||||
|
byte[] buf = new byte[len]; |
||||
|
inputStream.readFully(buf, 0, len); |
||||
|
|
||||
|
//TEST |
||||
|
System.out.println(new String(CeasarChipher.decrypt(buf))); |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
Main.console.error("An error occurred while reading"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
}); |
||||
|
t.start(); |
||||
|
} catch (Throwable e) { |
||||
|
Main.console.error("An error occurred while creating client!"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void write(byte[] buf) { |
||||
|
try { |
||||
|
outputStream.writeInt(buf.length); |
||||
|
outputStream.write(CeasarChipher.encrypt(buf)); |
||||
|
} catch (Throwable e) { |
||||
|
server.Main.console.error("An error occurred while writing data!"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package client.util; |
||||
|
|
||||
|
public class CeasarChipher { |
||||
|
|
||||
|
public static byte[] encrypt(byte[] x) { |
||||
|
for (int i = 0; i < x.length; ++i) { |
||||
|
x[i] = (byte) ((x[i] + 3) % 256); |
||||
|
} |
||||
|
return x; |
||||
|
} |
||||
|
|
||||
|
public static byte[] decrypt(byte[] x) { |
||||
|
for (int i = 0; i < x.length; ++i) { |
||||
|
x[i] = (byte) ((x[i] + 253) % 256); |
||||
|
} |
||||
|
return x; |
||||
|
} |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
package server; |
||||
|
|
||||
|
import server.log.EventLogger; |
||||
|
import server.net.ChatServer; |
||||
|
import server.util.ServerBuilder; |
||||
|
|
||||
|
public class Main { |
||||
|
|
||||
|
public static EventLogger console; |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
console = new EventLogger(System.out); |
||||
|
ChatServer server = ServerBuilder.buildServerFromConsoleArgs(args); |
||||
|
|
||||
|
if (server == null) { |
||||
|
console.info("Didn't initialize ChatServer!"); |
||||
|
console.close(); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
//Start the Server |
||||
|
server.start(); |
||||
|
|
||||
|
//console.close(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
package server.log; |
||||
|
|
||||
|
import java.io.PrintStream; |
||||
|
|
||||
|
public class EventLogger { |
||||
|
|
||||
|
private static final String ANSI_RESET = "\u001B[0m"; |
||||
|
private static final String ANSI_RED = "\u001B[31m"; |
||||
|
private static final String ANSI_GREEN = "\u001B[32m"; |
||||
|
private static final String ANSI_BLUE = "\u001B[34m"; |
||||
|
private static final String ANSI_WHITE = "\u001B[37m"; |
||||
|
private final PrintStream stream; |
||||
|
|
||||
|
public EventLogger(PrintStream stream) { |
||||
|
this.stream = stream; |
||||
|
} |
||||
|
|
||||
|
public void println(String msg) { |
||||
|
stream.println(msg); |
||||
|
} |
||||
|
|
||||
|
public void error(String msg) { |
||||
|
stream.println(ANSI_WHITE + "[" + ANSI_RED + "-" + ANSI_WHITE + "] " + msg + ANSI_RESET); |
||||
|
} |
||||
|
|
||||
|
public void info(String msg) { |
||||
|
stream.println(ANSI_WHITE + "[" + ANSI_BLUE + "*" + ANSI_WHITE + "] " + msg + ANSI_RESET); |
||||
|
} |
||||
|
|
||||
|
public void success(String msg) { |
||||
|
stream.println(ANSI_WHITE + "[" + ANSI_GREEN + "+" + ANSI_WHITE + "] " + msg + ANSI_RESET); |
||||
|
} |
||||
|
|
||||
|
public void close() { |
||||
|
stream.close(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
package server.net; |
||||
|
|
||||
|
import server.Main; |
||||
|
import server.util.CeasarChipher; |
||||
|
|
||||
|
import java.io.DataInputStream; |
||||
|
import java.io.DataOutputStream; |
||||
|
import java.io.IOException; |
||||
|
import java.net.Socket; |
||||
|
|
||||
|
public class ChatClient { |
||||
|
|
||||
|
private final int id; |
||||
|
private final Socket s; |
||||
|
private final DataInputStream inputStream; |
||||
|
private final DataOutputStream outputStream; |
||||
|
private final Thread t; |
||||
|
|
||||
|
public ChatClient(int id, Socket s, DataInputStream inputStream, DataOutputStream outputStream) { |
||||
|
this.id = id; |
||||
|
this.s = s; |
||||
|
this.inputStream = inputStream; |
||||
|
this.outputStream = outputStream; |
||||
|
t = new Thread(() -> { |
||||
|
try { |
||||
|
while (true) { |
||||
|
int len = inputStream.readInt(); |
||||
|
byte[] buf = new byte[len]; |
||||
|
inputStream.readFully(buf, 0, len); |
||||
|
|
||||
|
//TEST |
||||
|
System.out.println(new String(CeasarChipher.decrypt(buf))); |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
Main.console.error("An error occurred while reading from client (" + s.getRemoteSocketAddress().toString() + ") [id: " + id + "]"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
}); |
||||
|
try { |
||||
|
t.start(); |
||||
|
} catch (Throwable e) { |
||||
|
Main.console.error("An error occurred while starting client (" + s.getRemoteSocketAddress().toString() + ") [id: " + id + "]"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void write(byte[] buf) { |
||||
|
try { |
||||
|
outputStream.writeInt(buf.length); |
||||
|
outputStream.write(CeasarChipher.encrypt(buf)); |
||||
|
} catch (Throwable e) { |
||||
|
Main.console.error("An error occurred while writing data to client (" + s.getRemoteSocketAddress().toString() + ") [id: " + id + "]"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void disconnect() { |
||||
|
try { |
||||
|
t.stop(); |
||||
|
s.close(); |
||||
|
inputStream.close(); |
||||
|
outputStream.close(); |
||||
|
} catch (Throwable e) { |
||||
|
Main.console.error("An error occurred while disconnecting client (" + s.getRemoteSocketAddress().toString() + ") [id: " + id + "]"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,61 @@ |
|||||
|
package server.net; |
||||
|
|
||||
|
import server.Main; |
||||
|
import server.util.Queue; |
||||
|
|
||||
|
import java.io.DataInputStream; |
||||
|
import java.io.DataOutputStream; |
||||
|
import java.io.IOException; |
||||
|
import java.net.ServerSocket; |
||||
|
import java.net.Socket; |
||||
|
|
||||
|
public class ChatServer { |
||||
|
|
||||
|
private final int port; |
||||
|
private volatile int n_users; |
||||
|
private final Thread t; |
||||
|
private ServerSocket server; |
||||
|
private Queue<Integer> id_q; |
||||
|
|
||||
|
public ChatServer(int port, int max_users) { |
||||
|
Main.console.info("Initializing server on port: " + port + " with max_users: " + max_users); |
||||
|
this.port = port; |
||||
|
n_users = 0; |
||||
|
t = new Thread(() -> { |
||||
|
try { |
||||
|
while (true) { |
||||
|
if (n_users == max_users) continue; |
||||
|
Socket s = server.accept(); |
||||
|
DataInputStream inputStream = new DataInputStream(s.getInputStream()); |
||||
|
DataOutputStream outputStream = new DataOutputStream(s.getOutputStream()); |
||||
|
ChatClient client = new ChatClient(id_q.deq(), s, inputStream, outputStream); |
||||
|
n_users++; |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
Main.console.error("An error occurred while listening for connections!"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
}); |
||||
|
id_q = new Queue<>(max_users); |
||||
|
for (int i = 0; i < max_users; ++i) id_q.enq(i); |
||||
|
} |
||||
|
|
||||
|
public void start() { |
||||
|
try { |
||||
|
server = new ServerSocket(port); |
||||
|
t.start(); |
||||
|
} catch (Throwable e) { |
||||
|
Main.console.error("An error occurred while starting the ChatServer!"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void stop() { |
||||
|
try { |
||||
|
t.stop(); |
||||
|
} catch (Throwable e) { |
||||
|
Main.console.error("An error occurred while stopping the ChatServer!"); |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package server.util; |
||||
|
|
||||
|
public class CeasarChipher { |
||||
|
|
||||
|
public static byte[] encrypt(byte[] x) { |
||||
|
for (int i = 0; i < x.length; ++i) { |
||||
|
x[i] = (byte) ((x[i] + 3) % 256); |
||||
|
} |
||||
|
return x; |
||||
|
} |
||||
|
|
||||
|
public static byte[] decrypt(byte[] x) { |
||||
|
for (int i = 0; i < x.length; ++i) { |
||||
|
x[i] = (byte) ((x[i] + 253) % 256); |
||||
|
} |
||||
|
return x; |
||||
|
} |
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
package server.util; |
||||
|
|
||||
|
/* |
||||
|
!!! WORK IN PROGRESS !!! |
||||
|
|
||||
|
trying to implement a wait-free queue |
||||
|
*/ |
||||
|
|
||||
|
import java.util.concurrent.atomic.AtomicReferenceArray; |
||||
|
|
||||
|
public class Queue<T> { |
||||
|
|
||||
|
private volatile int head = 0, tail = 0; |
||||
|
private final int capacity; |
||||
|
private AtomicReferenceArray<T> items; |
||||
|
|
||||
|
public Queue(int capacity) { |
||||
|
this.capacity = capacity; |
||||
|
items = new AtomicReferenceArray<>(capacity); |
||||
|
} |
||||
|
|
||||
|
public boolean enq(T x) { |
||||
|
if (tail - head == capacity) return false; |
||||
|
items.set((tail + 1) % capacity, x); |
||||
|
tail++; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public T deq() { |
||||
|
if (tail - head == 0) return null; |
||||
|
T x = items.get((head + 1) % capacity); |
||||
|
head++; |
||||
|
return x; |
||||
|
} |
||||
|
} |
@ -0,0 +1,67 @@ |
|||||
|
package server.util; |
||||
|
|
||||
|
import server.Main; |
||||
|
import server.net.ChatServer; |
||||
|
|
||||
|
public class ServerBuilder { |
||||
|
|
||||
|
private static final int DEFAULT_PORT = 5000; |
||||
|
private static final int MAX_USERS = 5; |
||||
|
private static final String HELP_MSG = """ |
||||
|
-h, -help: prints this help message. |
||||
|
-p, -port: sets the port for the ChatServer |
||||
|
"""; |
||||
|
|
||||
|
public static ChatServer buildServerFromConsoleArgs(String[] args) { |
||||
|
int port = DEFAULT_PORT; |
||||
|
int max_users = MAX_USERS; |
||||
|
int ptr = 0; |
||||
|
while (ptr < args.length) { |
||||
|
switch (args[ptr]) { |
||||
|
case "-h": |
||||
|
case "-help": |
||||
|
if (ptr != 0 || args.length > 1) { |
||||
|
Main.console.error("You cannot use -h or -help in combination with other commands!"); |
||||
|
return null; |
||||
|
} |
||||
|
Main.console.println(HELP_MSG); |
||||
|
return null; |
||||
|
case "-p": |
||||
|
case "-port": |
||||
|
try { |
||||
|
if (++ptr == args.length) { |
||||
|
Main.console.error("Please enter a port-number (0 to 65536)!"); |
||||
|
return null; |
||||
|
} |
||||
|
port = Integer.parseInt(args[ptr], 10); |
||||
|
if (port < 0 || port >= 65536) { |
||||
|
Main.console.error("Please enter a valid port-number (0 to 65536)!"); |
||||
|
return null; |
||||
|
} |
||||
|
} catch (NumberFormatException e) { |
||||
|
Main.console.error("Please enter a valid port-number (0 to 65536)!"); |
||||
|
return null; |
||||
|
} |
||||
|
break; |
||||
|
case "-m": |
||||
|
case "-max_users": |
||||
|
try { |
||||
|
if (++ptr == args.length) { |
||||
|
Main.console.error("Please enter a user count!"); |
||||
|
return null; |
||||
|
} |
||||
|
max_users = Integer.parseInt(args[ptr], 10); |
||||
|
} catch (NumberFormatException e) { |
||||
|
Main.console.error("Please enter a valid user count!"); |
||||
|
return null; |
||||
|
} |
||||
|
break; |
||||
|
default: |
||||
|
Main.console.error("Couldn't parse argument: '" + args[ptr] + "', please try '-h' or '-help' for help."); |
||||
|
return null; |
||||
|
} |
||||
|
++ptr; |
||||
|
} |
||||
|
return new ChatServer(port, max_users); |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue