├── .idea ├── .gitignore ├── vcs.xml ├── misc.xml └── modules.xml ├── Multiple-Clients-Chat.iml ├── .gitignore ├── src ├── Server.java ├── ClientHandler.java └── Client.java └── README.md /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Multiple-Clients-Chat.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### IntelliJ IDEA ### 2 | out/ 3 | !**/src/main/**/out/ 4 | !**/src/test/**/out/ 5 | 6 | ### Eclipse ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | bin/ 15 | !**/src/main/**/bin/ 16 | !**/src/test/**/bin/ 17 | 18 | ### NetBeans ### 19 | /nbproject/private/ 20 | /nbbuild/ 21 | /dist/ 22 | /nbdist/ 23 | /.nb-gradle/ 24 | 25 | ### VS Code ### 26 | .vscode/ 27 | 28 | ### Mac OS ### 29 | .DS_Store 30 | 31 | Client$1.class 32 | Client.class 33 | ClientHandler.class 34 | Server.class -------------------------------------------------------------------------------- /src/Server.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.net.ServerSocket; 3 | import java.net.Socket; 4 | 5 | public class Server { 6 | 7 | private ServerSocket serverSocket; 8 | 9 | public Server(ServerSocket serverSocket) { 10 | this.serverSocket = serverSocket; 11 | } 12 | 13 | public void startServer() { 14 | 15 | try { 16 | 17 | while (!serverSocket.isClosed()) { 18 | 19 | Socket socket = serverSocket.accept(); 20 | System.out.println("A new client has connected!"); 21 | 22 | ClientHandler clientHandler = new ClientHandler(socket); 23 | 24 | Thread thread = new Thread(clientHandler); 25 | thread.start(); 26 | 27 | } 28 | 29 | } catch (IOException e) { 30 | 31 | e.printStackTrace(); 32 | 33 | } 34 | 35 | } 36 | 37 | public void closeServerSocket() { 38 | try { 39 | 40 | if (serverSocket != null) serverSocket.close(); 41 | 42 | 43 | } catch (IOException e) { 44 | 45 | e.printStackTrace(); 46 | 47 | } 48 | } 49 | 50 | public static void main(String[] args) throws IOException{ 51 | 52 | int port = 1234; 53 | ServerSocket serverSocket = new ServerSocket(port); 54 | Server server = new Server(serverSocket); 55 | System.out.println("Server started in Port: " + port); 56 | System.out.println("Listening..."); 57 | server.startServer(); 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## O que é isso? 3 | 4 | Um Chat Multiusuário é uma aplicação de bate-papo, que permite que várias pessoas se comuniquem entre si em tempo real, usando apenas o terminal (linha de comando). 5 | 6 | ## Objetivos do projeto 7 | 8 | - Aprender programação de redes em especial WebSocket. 9 | - Entender melhor como funciona a comunicação entre computadores (Cliente-Servidor). 10 | - Trabalhar com a Interface de Linha de Comando (CLI). 11 | - Praticar Programação Concorrente com Threads. 12 | - Desenvolver a lógica de programação. 13 | 14 | ## Requisitos 15 | 16 | - Java JDK 8+ instalado. 17 | - Terminal ou prompt de comando. 18 | - Arquivos `Server.java`, `Client.java` e `ClientHandler.java` compilados. 19 | 20 | ## Como rodar? 21 | 22 | 1. Clone ou baixe o projeto no seu computador. 23 | 2. Abra o terminal na pasta do projeto. 24 | 3. Compile todos os arquivos Java: 25 | ``` 26 | javac Server.java Client.java ClientHandler.java 27 | ``` 28 | 29 | 4. Inicie o servidor (em uma aba/janela do terminal): 30 | ``` 31 | java Server 32 | ``` 33 | 34 | 5. Abra outro terminal e execute um cliente: 35 | ``` 36 | java Client 37 | ``` 38 | 39 | 6. Digite seu nome de usuário e comece a enviar mensagens para o grupo. 40 | ## **Fluxo de comunicação** 41 | 42 | 1. Cliente se conecta → manda o nome para o servidor. 43 | 44 | 2. Servidor cria um `ClientHandler` para ele. 45 | 46 | 3. Quando cliente envia mensagem: 47 | 48 | - Vai para o servidor. 49 | 50 | - Servidor repassa (`broadcast`) para todos os outros clientes. 51 | 52 | 4. Quando servidor envia algo para o cliente: 53 | 54 | - A thread de `listenForMessage()` lê e imprime no terminal. 55 | 56 | ## Perigos 57 | 58 | Se você abrir sua porta para a internet (por exemplo, fazendo port forwarding no seu roteador), qualquer pessoa com seu IP público e a porta poderá tentar se conectar ao seu servidor. 59 | 60 | As mensagens trocadas entre os clientes e o servidor podem ser interceptadas se você estiver enviando dados em texto puro, sem criptografia. 61 | 62 | Da forma como o projeto foi implementado (somente para estudo e testes), **deve apenas ser usado na sua rede local.** -------------------------------------------------------------------------------- /src/ClientHandler.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.net.Socket; 3 | import java.util.ArrayList; 4 | 5 | public class ClientHandler implements Runnable { 6 | 7 | public static ArrayList clientHandlers = new ArrayList<>(); 8 | private Socket socket; 9 | private BufferedReader bufferedReader; 10 | private BufferedWriter bufferedWriter; 11 | private String clientUsername; 12 | 13 | public ClientHandler(Socket socket) { 14 | 15 | try { 16 | 17 | this.socket = socket; 18 | this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 19 | this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 20 | this.clientUsername = bufferedReader.readLine(); 21 | clientHandlers.add(this); 22 | broadcastMessage("SERVER: " + clientUsername + " has entered the chat!"); 23 | 24 | } catch (IOException e) { 25 | 26 | closeEverything(socket, bufferedReader, bufferedWriter); 27 | 28 | } 29 | 30 | } 31 | 32 | @Override 33 | public void run() { 34 | 35 | String messageFromClient; 36 | 37 | while (socket.isConnected()) { 38 | 39 | try { 40 | 41 | messageFromClient = bufferedReader.readLine(); 42 | broadcastMessage(messageFromClient); 43 | 44 | } catch (IOException e) { 45 | 46 | closeEverything(socket, bufferedReader, bufferedWriter); 47 | break; 48 | 49 | } 50 | 51 | } 52 | 53 | } 54 | 55 | public void broadcastMessage(String messageToSend) { 56 | 57 | for (ClientHandler clientHandler : clientHandlers) { 58 | 59 | try { 60 | 61 | if (!clientHandler.clientUsername.equals(clientUsername)) { 62 | 63 | clientHandler.bufferedWriter.write(messageToSend); 64 | clientHandler.bufferedWriter.newLine(); 65 | clientHandler.bufferedWriter.flush(); 66 | 67 | } 68 | 69 | } catch (IOException e) { 70 | 71 | closeEverything(socket, bufferedReader, bufferedWriter); 72 | 73 | } 74 | 75 | } 76 | 77 | } 78 | 79 | public void removeClientHandler() { 80 | 81 | clientHandlers.remove(this); 82 | broadcastMessage("SERVER: " + clientUsername + " has left the chat!"); 83 | } 84 | 85 | public void closeEverything(Socket socket, BufferedReader bufferedReader, BufferedWriter bufferedWriter) { 86 | 87 | removeClientHandler(); 88 | try { 89 | 90 | if (bufferedReader != null) { 91 | 92 | bufferedReader.close(); 93 | 94 | } 95 | 96 | if (bufferedWriter != null) { 97 | 98 | bufferedWriter.close(); 99 | 100 | } 101 | 102 | if (socket != null) { 103 | 104 | socket.close(); 105 | 106 | } 107 | 108 | } catch (IOException e) { 109 | 110 | e.printStackTrace(); 111 | 112 | } 113 | 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/Client.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.net.Socket; 3 | import java.util.Scanner; 4 | 5 | public class Client { 6 | 7 | private Socket socket; 8 | private BufferedWriter bufferedWriter; 9 | private BufferedReader bufferedReader; 10 | private String username; 11 | 12 | public Client(Socket socket, String username) { 13 | 14 | try { 15 | 16 | this.socket = socket; 17 | this.bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); 18 | this.bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 19 | this.username = username; 20 | 21 | } catch (IOException e) { 22 | 23 | closeEverything(socket, bufferedReader, bufferedWriter); 24 | 25 | } 26 | 27 | } 28 | 29 | private volatile boolean running = true; 30 | 31 | public void sendMessage() { 32 | 33 | try { 34 | 35 | bufferedWriter.write(username); 36 | bufferedWriter.newLine(); 37 | bufferedWriter.flush(); 38 | 39 | Scanner scanner = new Scanner(System.in); 40 | 41 | while (running) { 42 | 43 | System.out.print(username + ": "); 44 | String messageToSend = scanner.nextLine(); 45 | 46 | if (messageToSend.trim().isEmpty()) { 47 | continue; 48 | } 49 | 50 | if (messageToSend.equalsIgnoreCase("/exit")) { 51 | running = false; 52 | bufferedWriter.write(username + " saiu do chat."); 53 | bufferedWriter.newLine(); 54 | bufferedWriter.flush(); 55 | 56 | closeEverything(socket, bufferedReader, bufferedWriter); 57 | } 58 | 59 | bufferedWriter.write(username + ": " + messageToSend); 60 | bufferedWriter.newLine(); 61 | bufferedWriter.flush(); 62 | 63 | } 64 | 65 | } catch (IOException e) { 66 | 67 | closeEverything(socket, bufferedReader, bufferedWriter); 68 | 69 | } 70 | 71 | } 72 | 73 | 74 | public void listenForMessage() { 75 | 76 | new Thread(() -> { 77 | 78 | String msgFromGroupChat; 79 | 80 | while (running) { 81 | 82 | try { 83 | 84 | msgFromGroupChat = bufferedReader.readLine(); 85 | 86 | if (msgFromGroupChat == null) { 87 | System.out.println("Servidor desconectado."); 88 | closeEverything(socket, bufferedReader, bufferedWriter); 89 | break; 90 | } 91 | 92 | System.out.println("\n" + msgFromGroupChat); 93 | 94 | System.out.print(username + ": "); 95 | 96 | } catch (IOException e) { 97 | 98 | closeEverything(socket, bufferedReader, bufferedWriter); 99 | break; 100 | } 101 | 102 | } 103 | closeEverything(socket, bufferedReader, bufferedWriter); 104 | System.exit(0); 105 | 106 | }).start(); 107 | 108 | } 109 | 110 | public void closeEverything(Socket socket, BufferedReader bufferedReader, BufferedWriter bufferedWriter) { 111 | 112 | try { 113 | 114 | if (bufferedReader != null) bufferedReader.close(); 115 | if (bufferedWriter != null) bufferedWriter.close(); 116 | if (socket != null) socket.close(); 117 | System.exit(0); 118 | 119 | } catch (IOException e) { 120 | 121 | e.printStackTrace(); 122 | 123 | } 124 | 125 | } 126 | 127 | public static void main(String[] args) throws IOException { 128 | 129 | System.out.println("-=-=-=-= GROUP CHAT -=-=-=-=-"); 130 | System.out.println(); 131 | 132 | Scanner scanner = new Scanner(System.in); 133 | System.out.println("Enter your username: "); 134 | String username = scanner.nextLine(); 135 | 136 | System.out.println("\n Bem-vindo ao chat, " + username + "!"); 137 | System.out.println("Digite suas mensagens e pressione Enter para enviar."); 138 | System.out.println("Digite /exit para sair do chat."); 139 | System.out.println("---------------------------------\n"); 140 | 141 | String ip = "localhost"; 142 | int port = 1234; 143 | Socket socket = new Socket(ip, port); 144 | 145 | Client client = new Client(socket, username); 146 | client.listenForMessage(); 147 | client.sendMessage(); 148 | 149 | } 150 | 151 | } 152 | --------------------------------------------------------------------------------