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