국비학원/공부

25일차 java(last) - ChatGUI make

mikan- 2023. 7. 3. 13:42

# ChatGUIClient

import java.net.*;//Socket클래스
import java.io.*;//입출력

// 2003년에 종료
import java.awt.*;//GUI
import java.awt.event.*;//event

//추가
import javax.swing.*;//JFrame,JTextArea,JTextField

class ChatGUIClient extends JFrame  implements ActionListener,Runnable
{
	JTextArea ta;//클라이언트의 대화를 출력
	JTextField tf;//입력
	//추가
	JScrollPane js;//스크롤바
    
	//---추가------
	Socket s; // 서버와 통신
	BufferedReader br;
	PrintWriter pw;
	String str, str1; // str : 서버, 대화에 출력할 문자열
	
	//-------------------------------------------
	
	public ChatGUIClient(){
       //객체생성 및 배치
	   ta = new JTextArea(); // 채팅창
	   tf = new JTextField(); // 입력창
	   
	   // 추가 -> NullPointerException
	   js = new JScrollPane(ta); // 채팅창이 결합된 스크롤바가 생성
	 
	   add(js,"Center");
	   add(tf,"South");//아래
	   tf.addActionListener(this);
	   setBounds(200,200,500,350); // x, y, width, height
	   setVisible(true);
	   tf.requestFocus();//커서입력

	   //종료
	   setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	   //서버와 연결하는 구문
	   try{
		   
		  // 1.접속할 컴퓨터ip주소,포트번호
		  s = new Socket("192.168.0.21", 5400);
		  System.out.println("s : " + s);
		  
		  // 입출력객체 생성
		  br = new BufferedReader(new InputStreamReader(s.getInputStream()));
		  System.out.println("client 의 br=>"+br);
		  // autoflush : 버퍼에 쌓아놓지 않고 바로바로 상대방에게 출력해줌
		  pw = new PrintWriter(s.getOutputStream(), true);
		  System.out.println("client 의 pw=>"+pw);
		  
	   }catch(Exception e){
		   System.out.println("접속오류="+e);
	   }
	   //Thread 객체를 생성->run()호출
	   Thread ct = new Thread(this);
	   ct.start();//run()
	}
    //run
	public void run() {
		//더 이상 입력받을 수 없을때까지 ->JTextArea
		try {
			// 서버가 보내준 글자를 출력 = JTextArea(출력할 메소드를 append() 라고 씀)
			while ((str1 = br.readLine()) != null) {
				ta.append(str1 + "\n"); // 상대방이 보내준 글자는 세로로출력
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// ActionListener 상속 -> Enter쳤을때 호출하는 메소드
	@Override
	public void actionPerformed(ActionEvent e) {
		
		// str : 내가 입력한거 보내주는거 / str1 : 상대방이 입력한거 보내주는거
		str = tf.getText(); // 입력란에 써준 글자
		tf.setText(""); // 새로 입력을 받기 위해
		pw.println(str);
		pw.flush();
		
	}
	public static void main(String[] args) 
	{
		new ChatGUIClient();
	}
}

 

# GUIChatServer

//서버역활 -> 1. 클라이언트와 접속 -> 접속정보 -> 아이디로 구분해서 누가 접속했는지 서버가 알려줌
import java.net.*; // ServerSocket, Socket
import java.io.*; // BufferedReader 클래스, .....
import java.util.Vector; // list계열(동적배열) -> 실시간으로 접속한 클라이언트 수 가 저장됨

public class ChatGUIServer {
	
	// 연결
	ServerSocket ss; // 클라이언트와 접속할 때만 필요
	
	// 통신
	Socket s; // 클라이언트와의 통신(문자열 전송)
	
	Vector v; // 실시간으로 접속한 클라이언트의 정보를 저장해야 되기 때문에 Vector가 필요함
	
	// 서로간의 클래스가 객체가 필요할 경우
	// 1. Thread 객체가 필요 -> 자기 클래스에 멤버변수에 선언한다. (has a 관계)
	ServerThread st;
	
	// 생성자
	public ChatGUIServer() {
		// 서버를 가동 -> 클라이언트 접속할때 기다린다.(무한루프)
		v = new Vector(); // 생성자에서는 다른 클래스 객체명 사용 가능함
						  // 반대로 생성자에서는 자신의 클래스 객체명이 사용 불가능 하므로 this를 붙여서 사용함
		try {
			ss = new ServerSocket(5400); // ss객체생성 하면서 포트54322 열기
			System.out.println("ss : " + ss); // null -> 객체생성 실패
			System.out.println("채팅서버 가동중.../");
			
			// 무한대기
			while (true) {
				s = ss.accept(); // 접속승인(클라이언트 ip(자기ip), 5432)
				System.out.println("Accepted from " + s); // 접속자가 오면 접속자의 정보 출력함
				
				// 생성자 -> ServerThread 객체를 생성 -> 매개변수로 전달
				st = new ServerThread(this, s);
				
				// 생성자 -> 다른메소드 호출
				this.addThread(st);
				
				// Thread를 가동
				st.start(); // -> run()
				
			}
		} catch (Exception e) {
			System.out.println("서버접속 실패! : " + e);
		}
	}
	
	// 1. 접속한 클라이언트의 정보를 Vector에 저장
	// call by Reference
	public void addThread(ServerThread st) {
		v.add(st);
	}
	
	// 2. 퇴장한 클라이언트의 정보를 Vector에서 삭제
	public void removeThread(ServerThread st) {
		v.remove(st);
	}
	
	// 3. 각 클라이언트에게 실시간으로 메세지를 전달시켜주는 메소드
	// broadcast 메소드
	public void broadCast(String str) { // 입장, 퇴장
		for (int i = 0; i < v.size(); i++) { // Vector는 제너릭 안주면 Object로 저장함
			                                 // 꺼낼때는 반드시 형변환 해야됨
			ServerThread st = (ServerThread)v.elementAt(i);
			st.send(str); // 뿌리는 역활
		}
	}
	
	public static void main(String[] args) {
		new ChatGUIServer(); // 익명객체형으로 생성자 가능
	}
}

// 쓰레드 기능 : 실시간으로 데이터를 전송
class ServerThread extends Thread {
	
	// 클라이언트와 통신하기 위해서
	Socket s ; 
	
	// broadCast()를 호출하기 위해서
	ChatGUIServer cg;
	
	// 입력용
	BufferedReader br;
	
	// 출력용
	PrintWriter pw;
	// BufferedWriter 안쓰는 이유
	// PrintWriter 에는 autoFlush 기능 때문에
	
	// 전달할 문자열
	String str;
	
	// 대화할 사람들 정보
	String name; // 대화명(id) -> 통신가능하다
	
	// ChatGUIServer 객체를 매개변수로 전달받는 이유
	// 서버를 두 번 생성이 안되기 때문
	public ServerThread (ChatGUIServer cg, Socket s) {
		this.cg = cg;
		this.s = s; // 접속한 클라이언트의 정보
		
		//데이터를 실시간으로 전송을 해주는 입출력스트림 필요
		try { // s.getInputStream() -> 상대방이 보내주는 출력데이터
			// System.in 은 키보드로 입력받는거, 즉 자기 자신의 채팅만 해당
			// 상대방의 입력 정보까지 받아야되기 때문에 getInputStream 사용
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			
			// autoflush : 버퍼에 쌓아놓지 않고 바로바로 상대방에게 출력해줌
			pw = new PrintWriter(s.getOutputStream(), true);
		} catch (Exception e) {
			System.out.println("연결실패(e) : " + e);
		}
	}
	
	// 데이터를 전송해주는 메소드(클라이언트)
	public void send(String str) {
		pw.print(str);
		pw.flush(); // autoflush 기능이 없다면 써줘야된다.
	}
	
	// 실시간 데이터를 전송, 받는 코딩 -> 클라이언트 전송
	@Override
	public void run() {
		try {
			// 그륩채팅
			pw.println("먼저 대화명을 입력하세요.");
			name = br.readLine(); // 상대방의 id
			System.out.println("name=>"+name);
			// 각 클라이언트에게 전달
			cg.broadCast("[" + name + "] 님이 입장하셨습니다.");
			
			while((str = br.readLine())!= null) {
				cg.broadCast("[" + name + "]" + str);
			}
			
		} catch (Exception e) { // 클라이언트종료 -> 연결해제(퇴장으로)간주
			// 접속자가 퇴장 -> 접속한 사람들에게 실시간 전송
			cg.removeThread(this); // 빠져나간사람
			cg.broadCast("[" + name + "]  님이 퇴장하셨습니다.");
			System.out.println(s.getInetAddress() + "의 연결이 종료됐습니다.");
			
		}
	}
}

'국비학원 > 공부' 카테고리의 다른 글

27일차 jsp(2)  (0) 2023.07.03
26일차 jsp(1)  (0) 2023.07.03
25일차 java(13)  (0) 2023.07.03
24일차 java(12)  (0) 2023.07.03
23일차 java(11)  (0) 2023.07.03