├── .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 |
--------------------------------------------------------------------------------