본문 바로가기
IT/자바 Java

자바로 만드는 멀티스레드 채팅 서버 만들기

by SidePower 2024. 11. 29.

 

멀티스레드 소켓 서버는 여러 클라이언트가 동시에 서버에 접속할 수 있도록 하는 구조입니다.

서버는 각 클라이언트와 독립된 통신을 유지하기 위해 스레드(Thread) 를 사용합니다.

 

자바로 간단한 채팅 서버와 클라이언트를 구현하면서 멀티스레드를 연습해 볼 거예요!

 

멀티스레드 채팅 서버 구현

아래는 간단한 멀티스레드 소켓 서버와 클라이언트 예제입니다.

 

서버 코드 (Server.java)

import java.io.*;
import java.net.*;
import java.util.*;

public class Server {
    private static final int PORT = 12345;
    private static Set<PrintWriter> clientWriters = Collections.synchronizedSet(new HashSet<>());

    public static void main(String[] args) {
        System.out.println("채팅 서버가 시작되었습니다!");

        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            while (true) {
                new ClientHandler(serverSocket.accept()).start();
            }
        } catch (IOException e) {
            System.err.println("서버 오류: " + e.getMessage());
        }
    }

    private static class ClientHandler extends Thread {
        private Socket socket;
        private PrintWriter out;

        public ClientHandler(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                out = new PrintWriter(socket.getOutputStream(), true);
                clientWriters.add(out);

                String message;
                while ((message = in.readLine()) != null) {
                    System.out.println("클라이언트 메시지: " + message);
                    broadcast(message);
                }
            } catch (IOException e) {
                System.err.println("클라이언트 연결 오류: " + e.getMessage());
            } finally {
                clientWriters.remove(out);
                try {
                    socket.close();
                } catch (IOException e) {
                    System.err.println("소켓 종료 오류: " + e.getMessage());
                }
            }
        }

        private void broadcast(String message) {
            for (PrintWriter writer : clientWriters) {
                writer.println(message);
            }
        }
    }
}

 

클라이언트 코드 (Client.java)

import java.io.*;
import java.net.*;

public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 12345);
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {

            System.out.println("서버에 연결되었습니다! 메시지를 입력하세요.");

            Thread listener = new Thread(() -> {
                try {
                    String message;
                    while ((message = in.readLine()) != null) {
                        System.out.println("서버로부터: " + message);
                    }
                } catch (IOException e) {
                    System.err.println("서버 메시지 수신 오류: " + e.getMessage());
                }
            });

            listener.start();

            String userInput;
            while ((userInput = console.readLine()) != null) {
                out.println(userInput);
            }

        } catch (IOException e) {
            System.err.println("서버 연결 오류: " + e.getMessage());
        }
    }
}

 

코드 설명

서버(Server.java)는 클라이언트가 접속할 때마다

새로운 스레드를 생성하여 각 클라이언트를 처리합니다.

클라이언트(Client.java)는

서버와 연결된 후, 사용자 입력을 서버로 보내고 서버의 응답을 출력합니다.

Collections.synchronizedSet()을 사용하여

여러 클라이언트가 동시에 메시지를 전송할 때 스레드 안전성을 보장합니다.

broadcast() 메서드는 모든 클라이언트에게 메시지를 전송합니다.

반응형

댓글