JAVA/Java 기초

TCP 채팅 프로그램.java

john_ 2023. 2. 1. 17:52
728x90

2023.02.01 - [JAVA/Java 기초] - JSON 데이터형식.java

 

JSON 데이터형식.java

JSON 네트워크로 전달하는 데이터 형식 두 개 이상의 속성이 있으면 객체 {}로 표기합니다. 두 개 이상의 값이 있으면 배열[]로 표기합니다. JSON 라이브러리 다운로드 : https://github.com/stleary/JSON-java

less-go.tistory.com

 

이전 내용에서 계속 됩니다


 

채팅 서버와 클라이언트 구현

  • TCP 네트워킹을 이용해서 채팅 서버와 클라이언트를 구현합니다.
  • 채팅 서버: ChatServer는 채팅 서버 실행 클래스로 클라이언트의 연결 요청을 수락하고 통신용 SocketClient를 생성하는 역할
  • 채팅 클라이언트 : 단일 클래스 ChatClient는 채팅 서버로 연결을 요청하고, 연결된 후에는 제일 먼저 대화명을 보내며 다음 서버와 메시지를 주고 받습니다.

 

 


//ChatServer부

package ChatPG2;

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); //스레드풀 100명제한
	Map<String, SocketClient> chatRoom =
			Collections.synchronizedMap(new HashMap<>());
		
	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 sc = new Scanner(System.in);
			
			while(true) {
				String key = sc.nextLine();
				if(key.equals("q")) break;
			}
			
			sc.close();
			chatServer.stop();
			
		}catch (IOException e) {
		}

	}
	
	// 메서드 : 서버 시작
	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.shutdown();
			chatRoom.values().stream().forEach(sc -> sc.close());
			System.out.println("[서버] 종료됨");
		}catch(IOException e1) {}
	}
}
결과 :
[서버] 시작됨
-----------------------------------------
서버를 종료하려면 q를 입력하고 Enter키를 입력 하세요.
-----------------------------------------
q
[서버] 종료됨

 


//SocketClient 부

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

import javax.sound.midi.Receiver;

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);	// 스트링 형태로 json 내용 보내기
			dos.flush();		// 사용한 메모리 정리
		}catch (IOException e) {}
	}
	
	//메서드 : 연결 종료
	public void close() {
		try {
			socket.close();	// 클라이언트에 대한 socket 끊기
		}catch(Exception e) {}
	}
}

//ChatClient부

import java.io.DataOutputStream;
import java.io.DataInputStream;
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("172.20.20.22", 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 e) {
				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 sc = new Scanner(System.in);
			System.out.println("대화명 입력 : ");
			chatClient.chatName = sc.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 = sc.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);
				}
			}
			sc.close();
			chatClient.unconnect();
			
		}catch(IOException e) {
			System.out.println("[클라이언트] 서버 연결 안됨");
		}
	}
}
728x90