[Java] 채팅 프로그램

kimwoody·2021년 9월 7일
0

간단한 채팅 프로그램 만들기

1. 채팅 서버

다수의 클라이언트에게 지속적으로 채팅 서비스를 제공

ChattingServer 클래스

  • 서버는 클라이언트의 접속을 대기 ServerSocketaccept() 사용
  • 클라이언트가 접속하면 socket 반환
  • ServerWorker 클래스 생성 시 socket을 할당
    ServerWorker serverWorker = new ServerWorker(socket);
  • Thread 생성 후 start()
    Thread serverWorkerThread = new Thread(serverWorker); serverWorkerThread.start();
  • 위 작업을 지속

ServerWorker 클래스

  • 클라이언트에게 채팅 서비스를 제공하는 로직을 가지고 있는 클래스
  • 클라이언드들의 메세지를 입력받아 접속한 모든 클라이언트에게 출력
  • 위 작업을 지속(exit을 입력받으면 클라이언트 종료)

2. 채팅 클라이언트

서버로 자신의 메세지를 출력하고, Thread와 서버로부터 오는 다른 클라이언트들의 메세지를 입력한다.

ChatClient 클래스

  • Socket 생성
  • setDaemon(true) -> ChatClient Thread가 종료될 때 ReceiverWorker도 함께 종료되도록 설정
  • 서버로 자신의 메세지를 보내는 기능 정의
    (Scanner로부터 입력받아 서버로 출력을 반복, exit를 입력하면 종료)

ReceiverWorker 클래스

  • 생성된 Socket을 이용해 다른 클라이언트들의 메세지를 입력받아 콘솔에 출력하는 작업을 지속적으로 한다.

3. 실습

서버

package step7.inst;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ChatServer {
	/*
	 *  ServerSocket 생성  
	 *  loop  
	 *  accept() 
	 *  ServerWorker 생성 
	 *  list.add(ServerWorker) 
	 *  Thread 생성 
	 *  start() 
	 */
	// client와 통신을 하는 객체(ServerWorker>socket)의 리스트를 관리  
	// 다수의 ServerWorker Thread에 의해 공유되어 사용되는 리스트이므로 thread-safe 하게 처리해본다(동기화 처리)
	// private ArrayList<ServerWorker> list=new ArrayList<ServerWorker>();
	private List<ServerWorker> list = Collections.synchronizedList(new ArrayList<ServerWorker>());
	
	public void go() throws IOException {
		ServerSocket serverSocket = null;
		
		try {
			serverSocket = new ServerSocket(5432);
			System.out.println("**ChatServer 실행**");
			
			while(true) {
				Socket socket = serverSocket.accept();
				ServerWorker serverWorker = new ServerWorker(socket);
				
				// list에 추가
				list.add(serverWorker);
				
				Thread serverWorkerThread = new Thread(serverWorker);
				serverWorkerThread.start();
			}
		} finally {
			if(serverSocket != null)
				serverSocket.close();
		}
	}
	
	/*
	 *  각각의 ServerWorker가 클라이언트로부터 입력받은 메세지를 
	 *  접속한 전체 클라이언트에게 출력하기 위한 메서드 
	 *  아래 메서드를 개별 ServerWorker의 run 메서드에서 호출해서 사용한다 
	 */
	public void sendMessage(String message) {
		//for loop 를 이용해 list에 있는 모든 ServerWorker 의 pw.println();
		for(int i=0; i<list.size(); i++) {
			list.get(i).pw.println(message);
		}
	}
	
	//nested class 
	public class ServerWorker implements Runnable{
		private Socket socket;	
		private String clientIp;
		private BufferedReader br;
		private PrintWriter pw;
		public ServerWorker(Socket socket) {
			super();
			this.socket = socket;
		}
		@Override
		public void run() {
			try {
				chatting();
			} catch (IOException e) {
				e.printStackTrace();
				System.out.println(clientIp + " 통신 중 오류 발생 " + e.getMessage());
			} finally {
				if(socket != null) {
					try {
						socket.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					// list에서 현재 객체를 삭제한다
					list.remove(this);
					System.out.println(clientIp + "님이 나가셨습니다");
					sendMessage(clientIp + "님이 나가셨습니다");
				}
			}
		}
		
		public void chatting() throws IOException {
			clientIp = socket.getInetAddress().toString();
			br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			pw = new PrintWriter(socket.getOutputStream(), true); // true: autoflush
			System.out.println(clientIp + "님이 입장하셨습니다");
			sendMessage(clientIp + "님이 입장하셨습니다"); // 접속한 모든 사용자에게 메세지를 전송한다
			
			while(true) {
				String message = br.readLine(); // 친구의 메세지를 입력받는다
				if(message == null || message.trim().equalsIgnoreCase("exit")) {
					break;
				}
				// 접속한 모든 사용자에게 메세지를 출력한다
				sendMessage(clientIp + "님:" + message);
			}
		}
	}
	
	public static void main(String[] args) {
		try {
			new ChatServer().go();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

클라이언트

package step7.inst;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

import common.IP;

public class ChatClient {
	private Socket socket;
	private BufferedReader br; // 친구들의 메세지를 입력
	private Scanner scanner; // 콘솔에서 입력
	private PrintWriter pw; // 콘솔에서 입력받은 자신의 메세지를 서버로 출력
	
	/*
	 *  Socket 생성 
	 *  ReceiverWorker 생성 , Thread 생성 , setDaemon(true) , start() 
	 *  콘솔로부터 입력받은 (Scanner) 메세지를 서버로 출력하는 기능을 구현 
	 *  ( exit 를 입력하면 종료 ) 
	 */
	public void go() throws UnknownHostException, IOException {
		try {
			socket = new Socket(IP.LOCAL, 5432);
			br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			scanner = new Scanner(System.in);
			pw = new PrintWriter(socket.getOutputStream(), true); // auto flush: buffer에 있는 데이터를 즉시 출력
			
			// 서버에서 메세지를 입력받을 스레드를 생성하고 start 시킨다
			ReceiverWorker worker = new ReceiverWorker();
			Thread receiverThread = new Thread(worker); // 친구들의 메세지를 입력받은 스레드를 생성
			receiverThread.setDaemon(true); // 자신을 실행시킨 thread가 종료되면 함께 종료 되도록 설정
			receiverThread.start();
			
			// 자신의 메세지를 서버로 출력하는 작업 정의
			System.out.println("**ChatClient 실행**");
			while(true) {
				String message = scanner.nextLine(); // 콘솔 상에서 대기하다가 사용자가 메세지 입력 후 엔터 누르면 동작
				pw.println(message);
				if(message.trim().equalsIgnoreCase("exit")) {
					break;
				}
			}
		} finally {
			if(scanner != null)
				scanner.close();
			if(socket != null)
				socket.close();
			System.out.println("**ChatClient 종료**");
		}
	}
	
	//nested class 
	public class ReceiverWorker implements Runnable{
		
		//서버에서 친구들의 메세지를 입력받아 콘솔에 출력한다 
		@Override
		public void run() {
			try {
				receiveMessage();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void receiveMessage() throws IOException {
			while(true) {
				String message = br.readLine();
				if(message == null)
					break;
				System.out.println(message);
			}
		}
	}
	
	public static void main(String[] args) {
		try {
			new ChatClient().go();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

0개의 댓글