19.7 TCP 채팅 프로그램
TCP 네트워킹을 이용해서 채팅 서버와 클라이언트를 구현할 수 있다.
채팅 서버
package ch19.sec07;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.json.JSONObject;
public class ChatServer {
// 필드
ServerSocket serverSocket;
ExecutorService threadPool = Executors.newFixedThreadPool(100);
Map<String, SocketClient> chatRoom = Collections.synchronizedMap(new HashMap<>());
// 메소드: 서버 시작
public void start() throws IOException {
serverSocket = new ServerSocket(50001);
System.out.println("[서버] 시작됨");
Thread thread = new Thread(() -> {
try {
while (true) {
Socket socket = serverSocket.accept();
SocketClient sc = new SocketClient(this, socket);
}
} catch (IOException e) {
}
});
thread.start();
}
// 메소드: 클라이언트 연결 시 SocketClient 생성 및 추가
public void addSocketClient(SocketClient socketClient) {
String key = socketClient.chatName + "@" + socketClient.clientIp;
chatRoom.put(key, socketClient);
System.out.println("입장: " + key);
System.out.println("현재 채팅자 수: " + chatRoom.size() + "\n");
}
// 메소드: 클라이언트 연결 종료 시 SocketClient 제거
public void removeSocketClient(SocketClient socketClient) {
String key = socketClient.chatName + "@" + socketClient.clientIp;
chatRoom.remove(key);
System.out.println("나감: " + key);
System.out.println("현재 채팅자 수: " + chatRoom.size() + "\n");
}
// 메소드: 모든 클라이언트에게 메시지 보냄
public void sendToAll(SocketClient sender, String message) {
JSONObject root = new JSONObject();
root.put("clientIp", sender.clientIp);
root.put("chatName", sender.chatName);
root.put("message", message);
String json = root.toString();
Collection<SocketClient> socketClients = chatRoom.values();
for (SocketClient sc : socketClients) {
if (sc == sender) continue;
sc.send(json);
}
}
// 메소드: 서버 종료
public void stop() {
try {
serverSocket.close();
threadPool.shutdownNow();
chatRoom.values().stream().forEach(sc -> sc.close());
System.out.println("[서버] 종료됨");
} catch (IOException e1) {}
}
// 메소드: 메인
public static void main(String[] args) {
try {
ChatServer chatServer = new ChatServer();
chatServer.start();
System.out.println("--------------------------------------------------------------------");
System.out.println("서버를 종료하려면 q를 입력하고 Enter 키를 입력하세요.");
System.out.println("--------------------------------------------------------------------");
Scanner scanner = new Scanner(System.in);
while (true) {
String key = scanner.nextLine();
if (key.equals("q")) break;
}
scanner.close();
chatServer.stop();
} catch (IOException e) {
System.out.println("[서버] " + e.getMessage());
}
}
}
package ch19.sec07;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.json.JSONObject;
public class SocketClient {
// 필드
ChatServer chatServer;
Socket socket;
DataInputStream dis;
DataOutputStream dos;
String clientIp;
String chatName;
// 생성자
public SocketClient(ChatServer chatServer, Socket socket) {
try {
this.chatServer = chatServer;
this.socket = socket;
this.dis = new DataInputStream(socket.getInputStream());
this.dos = new DataOutputStream(socket.getOutputStream());
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
this.clientIp = isa.getHostName();
receive();
} catch (IOException e) {
}
}
// 메소드: JSON 받기
public void receive() {
chatServer.threadPool.execute(() -> {
try {
while (true) {
String receiveJson = dis.readUTF();
JSONObject jsonObject = new JSONObject(receiveJson);
String command = jsonObject.getString("command");
switch (command) {
case "incoming":
this.chatName = jsonObject.getString("data");
chatServer.sendToAll(this, "들어오셨습니다.");
chatServer.addSocketClient(this);
break;
case "message":
String message = jsonObject.getString("data");
chatServer.sendToAll(this, message);
break;
}
}
} catch (IOException e) {
chatServer.sendToAll(this, "나가셨습니다.");
chatServer.removeSocketClient(this);
}
});
}
// 메소드: JSON 보내기
public void send(String json) {
try {
dos.writeUTF(json);
dos.flush();
} catch (IOException e) {
}
}
// 메소드: 연결 종료
public void close() {
try {
socket.close();
} catch (Exception e) {}
}
}
채팅 클라이언트
package ch19.sec07;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
import org.json.JSONObject;
public class ChatClient {
// 필드
Socket socket;
DataInputStream dis;
DataOutputStream dos;
String chatName;
// 메소드: 서버 연결
public void connect() throws IOException {
socket = new Socket("localhost", 50001);
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
System.out.println("[클라이언트] 서버에 연결됨");
}
// 메소드: JSON 받기
public void receive() {
Thread thread = new Thread(() -> {
try {
while (true) {
String json = dis.readUTF();
JSONObject root = new JSONObject(json);
String clientIp = root.getString("clientIp");
String chatName = root.getString("chatName");
String message = root.getString("message");
System.out.println("<" + chatName + "@" + clientIp + "> " + message);
}
} catch (Exception e1) {
System.out.println("[클라이언트] 서버 연결 끊김");
System.exit(0);
}
});
thread.start();
}
// 메소드: JSON 보내기
public void send(String json) throws IOException {
dos.writeUTF(json);
dos.flush();
}
// 메소드: 서버 연결 종료
public void unconnect() throws IOException {
socket.close();
}
// 메소드: 메인
public static void main(String[] args) {
try {
ChatClient chatClient = new ChatClient();
chatClient.connect();
Scanner scanner = new Scanner(System.in);
System.out.println("대화명 입력: ");
chatClient.chatName = scanner.nextLine();
JSONObject jsonObject = new JSONObject();
jsonObject.put("command", "incoming");
jsonObject.put("data", chatClient.chatName);
String json = jsonObject.toString();
chatClient.send(json);
chatClient.receive();
System.out.println("--------------------------------------------------------------------");
System.out.println("보낼 메시지를 입력하고 Enter");
System.out.println("채팅를 종료하려면 q를 입력하고 Enter");
System.out.println("--------------------------------------------------------------------");
while (true) {
String message = scanner.nextLine();
if (message.toLowerCase().equals("q")) {
break;
} else {
jsonObject = new JSONObject();
jsonObject.put("command", "message");
jsonObject.put("data", message);
json = jsonObject.toString();
chatClient.send(json);
}
}
scanner.close();
chatClient.unconnect();
} catch (IOException e) {
System.out.println("[클라이언트] 서버 연결 안됨");
}
}
}
서브목차