JAVA 프로그래밍

문제

채팅 GUI 클라이언트 문제입니다 이를 해결하는 다음 프로그램을 해석하세요 
 

알고리즘

채팅 네트워크 클라이언트 초기화 
   네트워크 클라이언트 연결 초기화
      클라이언트에서 서버로 연결 요청
      네트워크 입출력 연결 후 데이터가 도착할 때까지 대기

대화 내용 입력시 상대편에게 전송
   입력한 대화 내용 읽기
   상대편에게 네트워크로 데이터 전송

대화 내용 도착시 채팅 화면 업데이트
   상대편이 네트워크로 보낸 데이터 읽기
   채팅 화면에 읽은 대화 내용 쓰기

채팅 네트워크 종료
   네트워크 종료

  채팅 GUI 클라이언트 프로그램의 GUI 및 클래스 다이어그램

 

  채팅 GUI 클라이언트 프로그램의 네트워크 연결 초기화 과정

 

  채팅 GUI 클라이언트 프로그램의 서버에서 클라이언트로 데이터 전송 과정

 

  채팅 GUI 클라이언트 프로그램의 클라이언트에서 서버로 데이터 전송 과정

 

  채팅 GUI 클라이언트 프로그램의 네트워크 종료 과정

 
 

프로그램 코드

E001	// 클라이언트에서 연결 요청하면 서버는 네트워크 연결 초기화
E002	// 서버 데이터가 도착할 때까지 계속 대기
E003	// (수신전용스레드와 별개로) 메인 스레드 N41 이후 실행중
E004	// 대화를 입력할 때까지 계속 대기
E005	// '안녕하세요' 입력
E006	// 서버로 데이터([CHAT] [클라이언트2]안녕하세요) 전송
E007	// 서버에서 보낸 데이터([CHAT] [클라이언트1]반갑습니다) 도착
E008	// 프로그램 닫기(우측상단 X) 선택
E009	// 메인스레드와 수신전용스레드가 모두 종료하여 프로그램 종료
	 
	// 파일명 : ./Chapter18/ChatGUIClient.java
	import javax.swing.*;
	import java.awt.*;
	import java.awt.event.*;
	import chat.ChatNetworkPanel;
	 
	// 채팅 GUI 클라이언트
	public class ChatGUIClient
	{
1		public static void main( String[] args ) {
			String serverIP = "localhost";
2			ChatNetworkPanel panel =
3			                    new ChatNetworkPanel( serverIP );
	 
			JFrame frame = new JFrame( "채팅(클라이언트)" );
			frame.getContentPane().add( panel );
			frame.addWindowListener( new WindowAdapter() {
Wb				public void windowClosing( WindowEvent event ) {
W1					panel.close();
We				}
			} );
			 
			frame.setPreferredSize( new Dimension( 320, 445 ) );
			frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
			frame.pack();
			frame.setVisible(true);
4		}
	}
	 
	// 파일명 : ./src/chat/ChatNetworkPanel.java
	package chat;
	import javax.swing.*;
	import java.awt.*;
	import java.awt.event.*;
	import network.Network;
	 
	// 채팅 네트워크 패널 클래스
	public class ChatNetworkPanel extends JPanel implements ActionListener, Runnable
	{
		private JTextArea  chatWindow;
		private JTextField inputField;
		private Network network;
		private String  id;
		private final String header = "[CHAT] ";
		 
		// 채팅 패널 초기화
CN1b		public ChatNetworkPanel() {
			// 채팅창
			chatWindow = new JTextArea();
			chatWindow.setBackground( Color.lightGray );
			chatWindow.setEditable( false );
			chatWindow.setLineWrap( true );
 
			// 채팅창이 길어지면 스크롤 활성화
			JScrollPane scroll = new JScrollPane( chatWindow );
			scroll.setPreferredSize( new Dimension( 290, 360 ) );
			add( scroll );
 
			// 입력창
			inputField = new JTextField();
			inputField.setPreferredSize( new Dimension( 290, 30 ) );
			inputField.addActionListener( this );
			inputField.requestFocus();
			add( inputField );
			setVisible( true );
CN1e		}
	 
		// 채팅 네트워크 클라이언트 초기화  
CN2b		public ChatNetworkPanel( String serverIP ) {
			// 채팅 패널 초기화
CN21			this();
	 
			// 네트워크 초기화
CN22			network =
CN23			          new Network();
CN24			network.connectAsClient( serverIP, this );
	 
			// 대화명 입력
			id = "[" + JOptionPane.showInputDialog( this, "아이디를 입력해주세요.", "아이디" ) + "]";
			network.write( header + id + "님이 들어오셨습니다" );
CN2e		}
 
		// 대화 내용 입력시 상대편에게 전송 
		@Override
CN3b		public void actionPerformed( ActionEvent event ) {
			// 입력한 대화 내용 읽기 
			String message = inputField.getText();
			// 상대편에게 네트워크로 대화 내용 전송
CN31			network.write( header + id + message );
			inputField.setText( "" );
CN3e		}
	 
		// 대화 내용 도착시 채팅 화면 업데이트 
		@Override
CN4b		public void run() {
			// 상대편이 네트워크로 보낸 데이터 읽기 
CN41			for ( String message = null; ( message =
CN42			                                          network.read() )
			                                                          != null; ) {
				// 채팅 프로그램 대화 내용이 아니면 메시지 무시
				if ( !message.contains( header ) )
					continue;
	 
				// 채팅 화면에 읽은 대화 내용 쓰기 
CN43				chatWindow.append( message.substring( header.length() ) + "\n" );
				chatWindow.setCaretPosition( chatWindow.getText().length() );
CN44			}
CN4e		}
	 
		// 채팅 네트워크 종료 
CN5b		public void close() {
			network.write( header + " " + id + "님이 나가셨습니다" );
			// 네트워크 종료
CN51			network.close();
CN5e		}
	}
 
 
	// 파일명 : ./src/network/Network.java
	package network;
	import java.io.*;
	import java.net.*;
	 
	// 네트워크 연결 및 입출력 클래스
	public class Network
	{
		public static final int serverPort = 7700;
		protected ServerSocket serverSocket;
		protected Socket socket;
		private BufferedReader in;
		private PrintWriter out;
		private Thread waitForCounterpart;
	 
		// 네트워크 클래스 초기화
N1b		public Network() {
			serverSocket = null;
			socket = null;
			in = null;
			out = null;
			waitForCounterpart = null;
N1e		}
		 
		// 네트워크 서버 연결 초기화 
N2b		public void connectAsServer( Runnable obj ) {
			try {
				// 서버 소켓 연결 
				serverSocket = new ServerSocket( serverPort );
				// 클라이언트에서 서버로 연결 요청시 연결 활성화 
N21				socket =
N22				         serverSocket.accept();
				// 네트워크 입출력 연결 후 데이터가 도착할 때까지 대기 
N23				connectInOut( obj );
			} catch ( Exception e ) {
				e.printStackTrace();
			}
N2e		}
		 
		// 네트워크 클라이언트 연결 초기화 
N3b		public void connectAsClient( String serverIP, Runnable obj ) {
			try {
				// 클라이언트에서 서버로 연결 요청 
N31				socket =
N32				         new Socket( serverIP, serverPort );
				// 네트워크 입출력 연결 후 데이터가 도착할 때까지 대기 
N33				connectInOut( obj );
			} catch ( Exception e ) {
				e.printStackTrace();
			}
N3e		}
	 
		// 네트워크 입출력 초기화
N4b		public void connectInOut( Runnable obj ) {
			try {
				// 네트워크 입출력 연결
				in = new BufferedReader( new InputStreamReader( socket.getInputStream() ));
				out = new PrintWriter( socket.getOutputStream(), true );
				// 네트워크에 데이터가 도착할 때까지 대기 시작
				waitForCounterpart = new Thread( obj );
N41				waitForCounterpart.start();
			} catch ( Exception e ) {
				e.printStackTrace();
			}
N4e		}
		 
		// 상대편이 네트워크로 보낸 데이터 읽기
N5b		public String read() {
			try {
				if ( this.isConnecting() == true )
N51					return
N52					       in.readLine();
			} catch ( Exception e ) {
				e.printStackTrace();
			}
			 
			return null;
N5e		}
		 
		// 상대편에게 네트워크로 데이터 전송 
N6b		public void write( String data ) {
			try {
				if ( this.isConnecting() == true )
N61					out.println( data );
			} catch ( Exception e ) {
				e.printStackTrace();
			}
N6e		}
	 
		// 네트워크 연결 상태 확인
		public boolean isConnecting() {
			if ( ( socket != null )
					&& ( in != null )
					&& ( out != null )
					&& ( waitForCounterpart != null )
					&& ( waitForCounterpart.getState() != Thread.State.TERMINATED ) )
				return true;
			else
				return false;
		}
		 
		// 네트워크 종료 
N7b		public void close() {
			try {
				if ( waitForCounterpart != null ) {
					waitForCounterpart.interrupt();
					waitForCounterpart = null;
				}
				if ( in != null ) {
					in.close();
					in=null;
				}
				if ( out != null ) {
					out.flush();
					out.close();
					out = null;
				}
				if ( socket != null ) {
					socket.close();
					socket = null;
				}
				if ( serverSocket != null ) {
					serverSocket.close();
					serverSocket = null;
				}
			} catch ( Exception e ) {
				e.printStackTrace();
			}
N7e		}
	}

실행 순서

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