basic client/server structure

This commit is contained in:
2025-02-27 12:52:12 +01:00
parent 2917535e05
commit fed666200c
9 changed files with 381 additions and 5 deletions

View File

@@ -1,5 +0,0 @@
public class App {
public static void main(String[] args) throws Exception {
System.out.println("Hello, World!");
}
}

15
ChatApp/src/ChatApp.java Normal file
View File

@@ -0,0 +1,15 @@
import java.net.InetSocketAddress;
import client.Client;
import server.Server;
public class ChatApp {
public static void main(String[] args) throws Exception {
Server server = new Server(6665);
Client client = new Client(new InetSocketAddress("localhost", 6665));
while (true) {
}
}
}

View File

@@ -0,0 +1,35 @@
package client;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import network.protocol.packets.LoginPacket;
import network.protocol.packets.SendChatMessagePacket;
public class Client {
private final ClientConnexion connexion;
public Client(InetSocketAddress serverAddress) throws SocketException {
this.connexion = new ClientConnexion(new DatagramSocket(), serverAddress);
login("Moi");
}
private void login(String pseudo) {
try {
this.connexion.sendPacket(new LoginPacket(pseudo));
} catch (IOException e) {
e.printStackTrace();
}
}
public void SendChatMessage(String message) {
try {
this.connexion.sendPacket(new SendChatMessagePacket(message));
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,94 @@
package client;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import network.PacketHandler;
import network.SocketReader;
import network.SocketWriter;
import network.protocol.Packet;
import network.protocol.PacketVisitor;
import network.protocol.packets.ChatMessagePacket;
import network.protocol.packets.CreateRoomPacket;
import network.protocol.packets.JoinRoomPacket;
import network.protocol.packets.LeaveRoomPacket;
import network.protocol.packets.LoginPacket;
import network.protocol.packets.RequestRoomListPacket;
import network.protocol.packets.RoomListPacket;
import network.protocol.packets.SendChatMessagePacket;
import network.protocol.packets.ServerResponsePacket;
public class ClientConnexion implements PacketVisitor, PacketHandler{
private final InetSocketAddress serverAddress;
private final SocketWriter writer;
private final SocketReader reader;
public ClientConnexion(DatagramSocket socket, InetSocketAddress serverAddress) {
this.serverAddress = serverAddress;
this.writer = new SocketWriter(socket);
this.reader = new SocketReader(socket, this);
}
public void close() {
this.reader.stop();
}
public void sendPacket(Packet packet) throws IOException {
this.writer.sendPacket(packet, serverAddress);
}
@Override
public void handlePacket(Packet packet, InetSocketAddress address) {
// we assume that the packet comes from the server
visit(packet);
}
@Override
public void visitPacket(ChatMessagePacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(CreateRoomPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(JoinRoomPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(LeaveRoomPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(LoginPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(RequestRoomListPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(RoomListPacket packet) {
System.out.println("Handled room list !");
// throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(SendChatMessagePacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(ServerResponsePacket packet) {
System.out.println(packet.getResponse());
}
}

View File

@@ -0,0 +1,9 @@
package network;
import java.net.InetSocketAddress;
import network.protocol.Packet;
public interface PacketHandler {
void handlePacket(Packet packet, InetSocketAddress address);
}

View File

@@ -0,0 +1,48 @@
package network;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import network.protocol.Packet;
public class SocketReader {
private final DatagramSocket socket;
private final Thread readThread;
private final PacketHandler handler;
public SocketReader(DatagramSocket socket, PacketHandler handler) {
this.socket = socket;
this.handler = handler;
this.readThread = new Thread(this::readLoop);
this.readThread.start();
}
public void stop() {
this.readThread.interrupt();
}
private void readLoop() {
while (!Thread.interrupted()) {
try {
byte[] buffer = new byte[65535];
DatagramPacket dataPacket = new DatagramPacket(buffer, buffer.length);
socket.receive(dataPacket);
InetSocketAddress address = new InetSocketAddress(dataPacket.getAddress(), dataPacket.getPort());
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(dataPacket.getData()));
Packet packet = (Packet) ois.readObject();
this.handler.handlePacket(packet, address);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,30 @@
package network;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import network.protocol.Packet;
public class SocketWriter {
private final DatagramSocket socket;
public SocketWriter(DatagramSocket socket) {
this.socket = socket;
}
public void sendPacket(Packet packet, InetSocketAddress address) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(stream);
oos.writeObject(packet);
oos.flush();
byte[] data = stream.toByteArray();
DatagramPacket dataPacket = new DatagramPacket(data, data.length, address.getAddress(),
address.getPort());
this.socket.send(dataPacket);
}
}

View File

@@ -0,0 +1,52 @@
package server;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import network.PacketHandler;
import network.SocketReader;
import network.protocol.Packet;
public class Server implements PacketHandler {
private final DatagramSocket serverSocket;
private final Map<InetSocketAddress, ServerConnexion> connexions;
private final SocketReader reader;
private final ArrayList<String> roomNames;
public Server(int port) throws SocketException {
this.serverSocket = new DatagramSocket(port);
this.connexions = new HashMap<>();
this.reader = new SocketReader(serverSocket, this);
this.roomNames = new ArrayList<>();
}
public ArrayList<String> getRoomNames() {
return roomNames;
}
public void close() {
this.reader.stop();
}
public boolean hasChatterName(String pseudo) {
for (var entry : this.connexions.entrySet()) {
if (pseudo.equals(entry.getValue().getChatterName()))
return true;
}
return false;
}
@Override
public void handlePacket(Packet packet, InetSocketAddress address) {
if (!connexions.containsKey(address)) {
this.connexions.put(address, new ServerConnexion(this, serverSocket, address));
}
this.connexions.get(address).visit(packet);
}
}

View File

@@ -0,0 +1,98 @@
package server;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import network.SocketWriter;
import network.protocol.Packet;
import network.protocol.PacketVisitor;
import network.protocol.packets.ChatMessagePacket;
import network.protocol.packets.CreateRoomPacket;
import network.protocol.packets.JoinRoomPacket;
import network.protocol.packets.LeaveRoomPacket;
import network.protocol.packets.LoginPacket;
import network.protocol.packets.RequestRoomListPacket;
import network.protocol.packets.RoomListPacket;
import network.protocol.packets.SendChatMessagePacket;
import network.protocol.packets.ServerResponsePacket;
import network.protocol.packets.ServerResponsePacket.Response;
public class ServerConnexion implements PacketVisitor {
private final Server server;
private final InetSocketAddress clientAddress;
private final SocketWriter writer;
private String chatterName;
public ServerConnexion(Server server, DatagramSocket socket, InetSocketAddress clientAddress) {
this.clientAddress = clientAddress;
this.server = server;
this.writer = new SocketWriter(socket);
}
public String getChatterName() {
return this.chatterName;
}
public void sendPacket(Packet packet) {
try {
this.writer.sendPacket(packet, clientAddress);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void visitPacket(ChatMessagePacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(CreateRoomPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(JoinRoomPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(LeaveRoomPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(LoginPacket packet) {
if (server.hasChatterName(packet.getPseudo())) {
sendPacket(new ServerResponsePacket(Response.AuthError));
return;
}
this.chatterName = packet.getPseudo();
sendPacket(new RoomListPacket(server.getRoomNames()));
System.out.println("[Server] Chatter " + packet.getPseudo() + " connected !");
}
@Override
public void visitPacket(RequestRoomListPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(RoomListPacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(SendChatMessagePacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
@Override
public void visitPacket(ServerResponsePacket packet) {
throw new UnsupportedOperationException("Unimplemented method 'visitPacket'");
}
}