JAVA 프로그래밍

문제

1:n 채팅 서버 프로그램입니다 이를 해결하는 다음 프로그램을 해석하세요 
[Server] 서버 대기중
[Server] 클라이언트 연결 : Thread[Thread-0,5,main]
[Server] 클라이언트 연결 : Thread[Thread-1,5,main]
[Server] 데이터 도착 : Thread[Thread-1,5,main] [CHAT] [클라이언트2]안녕하세요
[Server] 데이터 전송 : Thread[Thread-0,5,main] [CHAT] [클라이언트2]안녕하세요
[Server] 데이터 전송 : Thread[Thread-1,5,main] [CHAT] [클라이언트2]안녕하세요
[Server] 데이터 도착 : Thread[Thread-0,5,main] [CHAT] [클라이언트1]반갑습니다
[Server] 데이터 전송 : Thread[Thread-0,5,main] [CHAT] [클라이언트1]반갑습니다
[Server] 데이터 전송 : Thread[Thread-1,5,main] [CHAT] [클라이언트1]반갑습니다 

알고리즘

멀티클라이언트 서버 초기화 
   서버 소켓 연결
   각 클라이언트마다 반복
      네트워크 연결 활성화
      네트워크 입출력 초기화
      클라이언트 전담 스레드 시작

담당 클라이언트에서 보낸 데이터를 읽기
   전체 클라이언트에게 데이터를 보내기

담당 클라이언트에게 데이터 보내기

멀티클라이언트 서버 종료
   클라이언트 전담 스레드 전체 종료
   서버 소켓 종료

  멀티클라이언트 서버 프로그램의 클래스 다이어그램

 

  멀티클라이언트 서버 프로그램의 네트워크 연결 초기화 과정

 

  멀티클라이언트 서버 프로그램의 데이터 전송 과정

 
 

프로그램 코드

E001	// 클라이언트에서 연결 요청할 때까지 계속 대기
E002	// [클라이언트1]에서 연결 요청하면 서버는 네트워크 연결 초기화
E003	// 클라이언트 데이터가 도착할 때까지 계속 대기
E004	// [클라이언트2]에서 연결 요청하면 서버는 네트워크 연결 초기화
E005	// (수신전용스레드와 별개로) 메인 스레드 S16 이후 실행중
E006	// [클라이언트2]에서 보낸 데이터([CHAT] [클라이언트2]안녕하세요)가 도착
E007	// 데이터([CHAT] [클라이언트2]안녕하세요)를 [클라이언트1]에게 전송
E008	// 데이터([CHAT] [클라이언트2]안녕하세요)를 [클라이언트2]에게 전송
E009	// [클라이언트1]에서 보낸 데이터([CHAT] [클라이언트1]반갑습니다)가 도착
E010	// 데이터([CHAT] [클라이언트1]반갑습니다)를 [클라이언트1]에게 전송
E011	// 데이터([CHAT] [클라이언트1]반갑습니다)를 [클라이언트2]에게 전송
	 
	// 파일명 : ./Chapter18/MultiClientServer_Main.java
	import network.MultiClientServer;
	 
	// 멀티클라이언트 서버 Main 클래스
	public class MultiClientServer_Main
	{
1		public static void main( String[] args ) {
2			new MultiClientServer();
3		}
	}
 
	// 파일명 : ./src/network/MultiClientServer.java
	package network;
	import java.net.*;
	import java.util.*;
	 
	// 멀티클라이언트 서버 클래스
	public class MultiClientServer
	{
		private ServerSocket serverSocket;
		private ArrayList<ThreadPerClient> clients;
		  
		// 멀티클라이언트 서버 초기화 
S1b		public MultiClientServer() {
			try {
				// 서버 소켓 연결 
				serverSocket = new ServerSocket( Network.serverPort );
				clients = new ArrayList<ThreadPerClient>();
				System.out.println( "[Server] 서버 대기중" );
	 
				// 각 클라이언트마다 반복 
S11				while ( true ) {
					// 네트워크 연결 활성화 
S12					Socket socket =
S13					                serverSocket.accept();
					// 네트워크 입출력 초기화 
S14					ThreadPerClient client =
S15					                         new ThreadPerClient( socket, clients );
					clients.add( client );
					// 클라이언트 전담 스레드 시작 
S16					client.start();
S17					System.out.println( "[Server] 클라이언트 연결 : " + client );
				}
			} catch ( Exception e ) {
				close();
				e.printStackTrace();
			}
	 
S1e		}
		 
		// 멀티클라이언트 서버 종료 
		public void close() {
			try {
				// 클라이언트 전담 스레드 전체 종료 
				for ( ThreadPerClient client : clients ) {
					client.close();
					client.interrupt();
					clients.remove( client );
				}
	 
				// 서버 소켓 종료  
				if ( serverSocket != null ) {
					serverSocket.close();
					serverSocket = null;
				}
			} catch ( Exception e ) {
				e.printStackTrace();
			}
		}
	}
 
 
	// 파일명 : ./src/network/ThreadPerClient.java
	package network;
	import java.io.*;
	import java.net.*;
	import java.util.*;
	 
	// 클라이언트 전담 스레드
	public class ThreadPerClient extends Thread
	{
		private Socket socket;
		private BufferedReader in;
		private PrintWriter out;
		private ArrayList<ThreadPerClient> clients;
	 
		// 클라이언트 전담 스레드 초기화
C1b		public ThreadPerClient( Socket socket, ArrayList<ThreadPerClient> clients ) {
			super();
			try {
				// 네트워크 입출력 초기화
				this.in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
				this.out = new PrintWriter( socket.getOutputStream(), true );
				this.socket = socket;
				this.clients = clients;
			} catch ( Exception e ) {
				e.printStackTrace();
			}
C1e		}
	 
		// 클라이언트 전담 스레드 시작
		@Override
C2b		public void run() {
			try {
				// 담당 클라이언트에서 보낸 데이터를 읽기 
C21				for( String data = null; ( data =
C22				                                  in.readLine() )
				                                                 != null; ) {
					System.out.println("[Server] 데이터 도착 : " + this + " " + data );
					// 전체 클라이언트에게 데이터를 보내기 
C23					for( ThreadPerClient client : clients ) {
C24						client.write( data );
					}
C25				}
			} catch ( Exception e ) {
				close();
				e.printStackTrace();
			}
C2e		}
	 
		// 담당 클라이언트에게 데이터 보내기 
C3b		public void write( String data ) {
			try {
				// 담당 클라이언트와 네트워크 연결 종료시 데이터 전송 불가
				if ( this.getState() == Thread.State.TERMINATED ) {
					System.out.println( "[Server] 클라이언트 연결 해제 : " + this );
					close();
				}
				// 담당 클라이언트와 네트워크 연결 유효시 데이터 전송
				else if ( out != null ) {
					System.out.println("[Server] 데이터 전송 : " + this + " " + data );
C31					out.println( data );
				}
			} catch ( Exception e ) {
				e.printStackTrace();
			}
C3e		}
	 
		// 담당 클라이언트의 네트워크 종료
		public void close() {
			try {
				if( socket != null ) {
					socket.close();
					socket = null;
				}
				if( in != null ) {
					in.close();
					in = null;
				}
				if( out != null ) {
					out.close();
					out = null;
				}
			} catch ( Exception e ) {
				e.printStackTrace();
			}
		}
	}

실행 순서

 
 					※ 실행순서 및 메모리상태는 A키(이전) 및 D키(다음)를 눌러도 확인할 수 있습니다