# 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 |