티스토리 뷰

반응형

//다중 채팅 프로그램 


import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Scanner;
import java.util.StringTokenizer;


class ChattingClient extends Frame implements ActionListener {
   
	private static final long serialVersionUID = -6754116203125986830L;
	
Thread						listenThread; // 쓰레드
   Socket						socket; // 클라이언트 소켓
   BufferedReader		reader; // 입력 스트림
   BufferedWriter		writer; // 출력 스트림

   String						serverMsg; // 서버의 메시지
   String						clientMsg; // 클라이언트(누리꾼) 메시지 
   String						name; // 이름

   TextArea					ta; // 여러줄을 타이핑 할 수 있는 입력 컴포넌트
   TextField					tf; // 한줄만을 타이핑 할 수 있는 입력 컴포넌트
   List							list; // 컬렉션(목록) : 클라이언트(누리꾼)들의 목록
   Button						b; //  창닫기 버튼
   Panel						p1; // 패널
   Panel						p2; // 패널


// 생성자 : 초기화(누리꾼 닉네임, IP, 포트)

public ChattingClient(String userName, String HostIP, String HostPort) throws Exception {

		  super("["+userName+"] Cilent Window");
		  this.name=userName;

		  p1 = new Panel(); 
		  p2 = new Panel();

		  ta  = new TextArea(); // 채팅 상황 출력란 
		  tf   = new TextField(40); // 입력란

		  tf.addActionListener(this); // 이벤트 감지자(리스너) -> 입력란 정보 처리

		  list = new List(); // 클라이언트(누리꾼)들의 목록
		  b   = new Button("Exit"); // 창닫기 버튼
		  
		  // 창닫기 이벤트 핸들러
addWindowListener(new WindowAdapter(){  
	@Override  
		public void windowClosing(WindowEvent e) {  
		// TODO Auto-generated method stub  
		
			e.getWindow().setVisible(false); // 창(윈도우 : Frme)을 닫다; 메모리상에서는 여전히  
			e.getWindow().dispose(); // 메모리에서 제거  
			System.exit(0); // 프로그램 정상 종료  
	}  
});
		  // 끝

		  p1.setLayout(new GridLayout(1,2)); // 채팅창의 레이아웃 구성 
		  
		  // 컴포넌트 -> 컨테이너 추가
		  p1.add(ta); 
		  p1.add(list);
		  p2.add(tf); 
		  p2.add(b);
		  
		  add(p1,"Center"); // BorderLayout -> 채팅상황(채팅글 + 누리꾼들의 목록) : GridLayout
		  add(p2,"South"); // 입력란 
  
		  name   = userName; // 누리꾼 이름

	      InetAddress realHost = InetAddress.getByName(HostIP); // IP 처리
		  int realPort = Integer.parseInt(HostPort); // 포트(port) 처리

     	  socket = new Socket(realHost, realPort ); 
     	  // 클라이언트 소켓을 생성 : 클라이언트당 1개씩 생성

		  reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		  // 소켓의 정보를 입력 스트림으로 처리 
		  writer  =  new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		  // 소켓의 정보를 출력스트림으로 처리 

		  sendMessage("001"+userName+"\n"); 
		  // 메시지를 보냄. 단 "001"은 단순한 접두어(클라이언트를 의미)임
  }
       

// 메시지를 감지하는 메소드
	   public void listenMessage(){ 

			  SocketThread listenThread = new SocketThread();
            
			  listenThread.setDaemon(true);
              listenThread.start();

       }

//  Stream/socket  Close 메소드
	public void closeAll(){  

		    try {
					   if(reader!=null) reader.close();
					   if(writer!=null) writer.close();
					   if(socket!=null) socket.close();
					   System.exit(0);
		
			 } catch(IOException ie) {
						System.out.println("IO Stream 예외처리 : " + ie.getMessage());
			 } catch(Exception e) {
					System.out.println("Close 예외처리 : " + e.getMessage());
			 } finally {
				 System.exit(0);
			 }

	  } // closeAll

// 메시지 전송 메소드
	public void sendMessage(String msg) {
      
	   try {
                    writer.write(msg+" \n");                    
                    writer.flush(); // Writer 출력 스트림을 초기화(비워버림)
               
		  } catch(IOException ie) {
				   System.out.println("Messaging IO 예외 처리 : " + ie.getMessage());
		  } catch(Exception e) {
			   System.out.println("예외 처리 : " + e.getMessage());
		
		  }
       }

// 	액션이 발생하면 불려지는 핸들러
	 public void actionPerformed(ActionEvent ae) {

			  sendMessage("002["+name+"]"+tf.getText()); // 메시지 전송
			  tf.setText(""); // 입력창 초기화 
	 
	 }

// Main 메소드
	public static void main(String args[]) { 

		  ChattingClient cl = null;
		  
		  System.out.println("클라이언트의 닉네임, 서버의 IP, 포트를 입력하세요");
		  Scanner scan = new Scanner(System.in);
		  
		  String name = scan.nextLine(); 
		  String ip = scan.nextLine();
		  String port = scan.nextLine();
	  
				  try {
							   // cl = new ChattingClient(args[0], args[1], args[2]);
					  		   cl = new ChattingClient(name, ip, port);

							   cl.setBounds(200,200,400,400);  // 사각형 영역의 경계를 크기만큼 지정함
							   cl.setVisible(true);

							   cl.listenMessage(); 
									  
				  } catch(Exception e){
						cl.closeAll();			  
				  }
    }  // main

	/*
	 *  Client Thread 
	 */
	class SocketThread extends Thread implements Runnable {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			  try {

					 while ( (serverMsg = reader.readLine()) != null ) {
						 //서버의 메시지를 입력 스트림(reader)에서 읽어들임 
	
							     System.out.println(serverMsg); // 서버의 메시지 출력

							 if  (serverMsg.startsWith("001")) { // 클라이언트 리스트
											  list.removeAll(); // 목록에서 모든 클라이언트를 제거

											  StringTokenizer st = new StringTokenizer(serverMsg.substring(3),"|");
			
											       while (st.hasMoreTokens()) 
											 		   list.add((String)st.nextToken());  // while(in) ; 클라이언트(누리꾼)목록

							 } else if (serverMsg.startsWith("002")) { // 채팅
									ta.append(serverMsg.substring(3)+"\n"); // 출력창(textArea)에 출력
							 } // if
					} // while(out) 

 } catch(Exception e){
		 System.out.println("Thread 예외처리 :" + e.getMessage());
 }finally {
	 closeAll();

} // try

} // run()

} // SocketThread
} // ChattingClient

 

채팅 클라이언트 부분

 

 

 

 

결과

 

 

서버를 구축한 상태에서 채팅 클라이언트 클래스를 실행시킨 후 닉네임, IP, 포트를 입력하면

그 서버의 채팅방에 입장이 가능하다.

 

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31