package ch14;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
//잘 안되는 경우 top 4
//1. 나도 모르는 사이 이클립스 서버가 돌아가고 있다. 배치파일에러가 나면 콘솔에 안뜬다...->cmd창에서 확인 후 서버꺼라
//2. 오타난 경우
//3. path가 잘못 지정된 경우
//4. 17로 컴파일 했는데, path가 11이면 오류난다.
public class ChatServer1 {
ServerSocket server;
int port = 8002;
Vector<ClientThread1> vc; //VECTOR에 ClientThread1값만 넣는다.
// vector에 모든 클래스타입을 저장할 수 있었다.버전업 후 제네릭 뒤에 <>를 해서 지정할 수 있다.
// vector : 객체를 담을 수 있는 객체.
// socket을 만들어야 inputStream/outputStream만들 수 있다.
public ChatServer1() {
try {
server = new ServerSocket(port);
vc = new Vector<ClientThread1>(); //같은 클래스내이니까 앞에 ChatServer1. 없어도 됨.
} catch (Exception e) {
e.printStackTrace();
System.err.println("Error in Server");
System.exit(1); //비정상적인 종료. 매개변수 0 : 정상적인 종료
// 다른 자바 프로그램에게 넘겨줄때 알려주기 위해서 0 또는 1을 사용한다.
}
System.out.println("*ChatServer1***********");
System.out.println("*Client 접속을 기다리고 있습니다.**");
System.out.println("******************");
try {
while(true) {
Socket sock = server.accept();
ClientThread1 ct = new ClientThread1(sock);
ct.start(); //thread 스케줄러에 등록 -> run method 호출
vc.addElement(ct); //ClientThread 객체를 vector에 저장
// vector장점: vector 데이터를 넣었다 뺐다 맘대로 가능. 사이즈가 유동적
// 전체 서버가 해야할 일은 다 끝남. 호출한 뒤 벡터에 저장. 나머지는 clientThread에서.(서로 주고받기)
}
} catch (Exception e) {
System.err.println("Error in sock");
e.printStackTrace();
}
}
// 모든 접속된 client에게 메세지 전달
public void sendAllMessage(String msg) {
for(int i =0; i<vc.size(); i++) {
// vector에 저장된 clidentThread를 순차적으로 가져옴
ClientThread1 ct = vc.get(i);
// clientThread 가지고 있는 각각의 메세지 보내는 메소드 호출. 반복처럼 모두에게 메세지가 보내진다.
ct.sendMessage(msg);
}
}
// client가 접속을 끊을 수 있다. -> vector에서 접속을 끊어야한다. 이사간 집에 우편보내는 꼴.
// 접속이 끊어진 clientThread는 벡터에서 제거
public void removeClient(ClientThread1 ct) {
vc.remove(ct);
}
class ClientThread1 extends Thread{ //여기서부터
Socket sock;
BufferedReader in;
PrintWriter out;
String id;
public ClientThread1(Socket sock) {
// echoThread에서 가져옴.
try {
this.sock = sock;
in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
System.out.println(sock + "접속됨.");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() { //고객들 메세지 주고받는 부분.
try {
// client가 처음으로 받는 메세지.
out.println("사용하실 아이디를 입력하세요.");
id = in.readLine();
// 모든 사용자들에게 접속한 사람의 welcome메세지 전달
sendAllMessage("[" + id +"님이 입장하셨습니다.");
String line = "";
while(true) {
line = in.readLine(); //메세지 들어올 때까지 대기상태
if(line == null)
break;
sendAllMessage("[" + id + "]" + line);
} //~while
in.close();
out.close();
// sock.close(); 혹시 여기인가.
removeClient(this);
} catch (Exception e) {
removeClient(this); //client쪽이 탁 놔버리면 여기로 온다.
// this: 현재 나 자신. 나 자신을 remove해버리겠다.
System.err.println(sock + "끊어짐.");
}
}
// client에게 메세지 전달 메서드
public void sendMessage(String msg) {
out.println(msg);
}
}
// 여기까지 ClientThread이다.
public static void main(String[] args) {
new ChatServer1();
}
}
package ch14;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ChatClient1 extends MFrame implements ActionListener, Runnable{
// implements는 @Override이 있어야 한다.
Button btn1, btn2;
TextField tf1, tf2;
TextArea ta;
Panel p1, p2;
BufferedReader in;
PrintWriter out;
int port = 8002;
String id;
// String str[] = {"바보","개새끼","새끼","자바","java"}; //api밑에 놓은 건 필드.
// 굳이 한다면 이 애는 밖에 꺼내놓는 것이 좋다.
// 메서드 밖에서 사용하는 게 좋다. 지역변수, 메서드
public ChatClient1() {
super(350,400);
setTitle("MyChat 1.0");
p1 = new Panel();
p1.setBackground(new Color(100,200,100));
p1.add(new Label("HOST ",Label.CENTER));
p1.add(tf1 = new TextField("127.0.0.1",25));
//p1.add(tf1 = new TextField("10.100.204.62",25));
p1.add(btn1 = new Button("Connect"));
p2 = new Panel();
p2.setBackground(new Color(100,200,100));
p2.add(new Label("CHAT ",Label.CENTER));
p2.add(tf2 = new TextField("",25));
p2.add(btn2 = new Button("SEND"));
tf1.addActionListener(this);
tf2.addActionListener(this);
btn1.addActionListener(this);
btn2.addActionListener(this);
add(p1,BorderLayout.NORTH);
add(ta=new TextArea());
add(p2,BorderLayout.SOUTH);
validate();//갱신
}
@Override
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if(obj == tf1 || obj == btn1) {
connect(tf1.getText().trim()); //trim 공백제거
tf1.setEnabled(false);
btn1.setEnabled(false);
tf2.requestFocus();
} else if(obj == tf2 || obj == btn2) {
// 빈값이면 서버에 보내지 않도록
String str = tf2.getText().trim();
if(str.length()==0) //만약 아무 글자도 들어있지 않다면
return; //메서드 종료. 중간에 return넣으면 break와 유사.
// if(filterStr(str)) { //금지어 포함
// ta.append("입력하신 글자는 금지어가 포함되어 있습니다.");
// tf2.setText("");
// tf2.requestFocus();
// return;
// }
if(id == null){//제일 처음에만 실행
id = str;
setTitle(getTitle() + "[" + id + "]");
ta.setText("채팅을 시작합니다.\n" );
}
String str2[] = {"바보","개새끼","새끼","자바","java"};
String filterword = "";
for(int i=0; i<str2.length; i++) {
filterword = str2[i];
if(str == filterword) {
return;
}
}
out.println(str); //반드시println으로 해야함. 서버로 입력한 문자열 보냄
tf2.setText(""); //초기화 시키고
tf2.requestFocus();
}
}//--actionPerformed
// 금지어 필터링
// public boolean filterStr(String target) {
// boolean flag = false; //default는 false다.
// for (int i = 0; i < str.length; i++) {
// if(target.contains(str[i])) {
// flag = true; //금지어 포함
// break;
// }
// }
// return flag; //포함되었다면 true, 아니면 false;
// }
@Override
//서버로 부터 메세지가 들어오면 반응하는 기능
public void run() {
try {
while(true) {
// 서버에서 메세지 전달되면 ta에 append
ta.append(in.readLine() + "\n");
// 채팅 메세지가 들어오면 자동으로 포커스가 이동한다. 하지만 다시 돌아오게 만듦.
tf2.requestFocus(); //채팅 입력창
// 접속과 동시에 사용자 id입력하라고 함.
}
} catch (Exception e) {
e.printStackTrace();
}
}//--run
public void connect(String host){
try {
Socket sock = new Socket(host,port); //host값 입력됨
in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
// 서버 접속 후 threads시작
Thread t = new Thread(this);
t.start(); //run메서드 호출
} catch (Exception e) {
e.printStackTrace();
}
}//--connect
public static void main(String[] args) {
new ChatClient1();
}
}
.bat사용해서 서버 만든다.
컴파일 버전과 jdk버전이 다르면 오류난다.(컴파일 버전이 더 높으면 무조건 오류)
awt 한글 깨짐 문제
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=tjdqo55&logNo=220861174517
package ch14;
public class ChatProtocol2 {
// (C->S) ID : aaa 프로토콜
// (S->C) CHALLIST : aaa; bbb; ccc; 강호동;
public static final String ID = "ID"; //앞에 프로토콜 붙여서 서버는 그것을 분석한다.
// (C->S) CHAT: 받는 아이디;메세지 ex)CHAT:bbb;밥먹자
// (S->C) CHAT: 보내는 아이디;메세지 ex)CHAT:aaa;밥먹자 //귓속말
public static final String CHAT = "CHAT";
// (C->S) CHATALL : 메세지
// (S->C) CHATALL : [보낸 아이디]메세지
public static final String CHATALL = "CHATALL";
// (C->S) MESSAGE : 받는 아이디;쪽지내용 ex)MESSAGE:bbb;지금어디?
// (S->C) MESSAGE : 보내는 아이디;쪽지내용 ex)MESSAGE:bbb;지금어디?
public static final String MESSAGE = "MESSAGE";
// (S->C) CHALLIST :aaa;bbb;ccc;강호동;
public static final String CHATLIST = "CHATLIST";
//구분지 -> 프로토콜:data(delimiter)delimeter
public static final String DM =":";
}
package ch14;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
//잘 안되는 경우 top 4
//1. 나도 모르는 사이 이클립스 서버가 돌아가고 있다. 배치파일에러가 나면 콘솔에 안뜬다...->cmd창에서 확인 후 서버꺼라
//2. 오타난 경우
//3. path가 잘못 지정된 경우
//4. 17로 컴파일 했는데, path가 11이면 오류난다.
public class ChatServer2 {
ServerSocket server;
int port = 8003;
Vector<ClientThread2> vc; //VECTOR에 ClientThread1값만 넣는다.
// vector에 모든 클래스타입을 저장할 수 있었다.버전업 후 제네릭 뒤에 <>를 해서 지정할 수 있다.
// vector : 객체를 담을 수 있는 객체.
// socket을 만들어야 inputStream/outputStream만들 수 있다.
public ChatServer2() {
try {
server = new ServerSocket(port);
vc = new Vector<ClientThread2>(); //같은 클래스내이니까 앞에 ChatServer1. 없어도 됨.
} catch (Exception e) {
e.printStackTrace();
System.err.println("Error in Server");
System.exit(1); //비정상적인 종료. 매개변수 0 : 정상적인 종료
// 다른 자바 프로그램에게 넘겨줄때 알려주기 위해서 0 또는 1을 사용한다.
}
System.out.println("*ChatServer2.0***********");
System.out.println("*Client 접속을 기다리고 있습니다.**");
System.out.println("******************");
try {
while(true) {
Socket sock = server.accept();
ClientThread2 ct = new ClientThread2(sock);
ct.start(); //thread 스케줄러에 등록 -> run method 호출
vc.addElement(ct); //ClientThread 객체를 vector에 저장
// vector장점: vector 데이터를 넣었다 뺐다 맘대로 가능. 사이즈가 유동적
// 전체 서버가 해야할 일은 다 끝남. 호출한 뒤 벡터에 저장. 나머지는 clientThread에서.(서로 주고받기)
}
} catch (Exception e) {
System.err.println("Error in sock");
e.printStackTrace();
}
}
// 모든 접속된 client에게 메세지 전달
public void sendAllMessage(String msg) {
for(int i =0; i<vc.size(); i++) {
// vector에 저장된 clidentThread를 순차적으로 가져옴
ClientThread2 ct = vc.get(i);
// clientThread 가지고 있는 각각의 메세지 보내는 메소드 호출. 반복처럼 모두에게 메세지가 보내진다.
ct.sendMessage(msg);
}
}
// client가 접속을 끊을 수 있다. -> vector에서 접속을 끊어야한다. 이사간 집에 우편보내는 꼴.
// 접속이 끊어진 clientThread는 벡터에서 제거
public void removeClient(ClientThread2 ct) {
vc.remove(ct);
}
// 접속된 모든 id리스트 ex)aaa;bbb;강호동;
// vector에 client값 가져온다.
public String getIds() {
String ids ="";
for (int i = 0; i < vc.size(); i++) {
ClientThread2 ct = vc.get(i);
ids += ct.id + ";";
}
return ids; //aaa;bbb;강호동;값 리턴
}
// 지정한 ClientThread2 검색(id활용)
public ClientThread2 findClient(String id) {
ClientThread2 ct = null;
for (int i = 0; i < vc.size(); i++) {
ct = vc.get(i);
if(id.equals(ct.id)) {
break; //원하는 값을 찾으면 멈춘다. 더 하지 않는다.
} //--if
} // -- for
return ct;
}
class ClientThread2 extends Thread{ //여기서부터
Socket sock;
BufferedReader in;
PrintWriter out;
String id;
public ClientThread2(Socket sock) {
// echoThread에서 가져옴.
try {
this.sock = sock;
in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
System.out.println(sock + "접속됨.");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() { //고객들 메세지 주고받는 부분.
try {
// client가 처음으로 받는 메세지.
out.println("사용하실 아이디를 입력하세요.");
// 이 주석한 부분은 다 날린다.
// id = in.readLine();
// 모든 사용자들에게 접속한 사람의 welcome메세지 전달
// sendAllMessage("[" + id +"님이 입장하셨습니다.");
// String line = "";
// while(true) {
// line = in.readLine(); //메세지 들어올 때까지 대기상태
// if(line == null)
// break;
// sendAllMessage("[" + id + "]" + line);
// } //~while
while(true) {
String line = in.readLine();
if(line == null)
break;
else
routine(line);
}
in.close();//현재 로직으로는 불가능한 코드.
out.close();
sock.close();
removeClient(this);
} catch (Exception e) {
removeClient(this); //client쪽이 탁 놔버리면 여기로 온다.
// this: 현재 나 자신. 나 자신을 remove해버리겠다.
System.err.println(sock + "끊어짐.");
}
}
public void routine(String line) {
// CHATALL:[aaa] 오늘은 월요일입니다.
System.out.println(line);
int idx = line.indexOf(ChatProtocol2.DM);
String cmd = line.substring(0,idx); //0부터 idx까지 = CHATALL
String data = line.substring(idx + 1); //[aaa]오늘은 월요일입니다.
if(cmd.equals(ChatProtocol2.ID)) {
id = data; //aaa
//새로운 접속자가 추가되었기 때문에 리스트 재전송
sendAllMessage(ChatProtocol2.CHATLIST + ChatProtocol2.DM + getIds());
//welcome 메세지 전송
sendAllMessage(ChatProtocol2.CHATALL + ChatProtocol2.DM + "[" + id + "]님이 입장하였습니다.");
} else if(cmd.equals(ChatProtocol2.CHAT)) {
// data :bbb;밥먹자(aaa가 보냄)
idx = data.indexOf(';'); //;위치값을 가져오는게 idx
cmd = data.substring(0,idx);//bbb
data = data.substring(idx + 1); //data
ClientThread2 ct = findClient(cmd);
if(ct != null) { //현재 접속자
// ct는 bbb 클라이언트스레드
ct.sendMessage(ChatProtocol2.CHAT + ChatProtocol2.DM +"["
+ id + "(S)]" + data); //CHAT:[aaa(S)] 밥먹자=>bbb에게 넘어간다.
sendMessage(ChatProtocol2.CHAT + ChatProtocol2.DM +"["
+ id + "(S)]" + data);
}else { //bbb가 접속이 안된 경우
sendMessage(ChatProtocol2.CHAT + ChatProtocol2.DM + "["
+ cmd + "]님 접속자가 아닙니다.");
}
} else if(cmd.equals(ChatProtocol2.MESSAGE)) {
idx = data.indexOf(';'); //;위치값을 가져오는게 idx
cmd = data.substring(0,idx);//bbb
data = data.substring(idx + 1); //data
ClientThread2 ct = findClient(cmd);
if(ct != null) { //현재 접속자
// ct는 bbb 클라이언트스레드
ct.sendMessage(ChatProtocol2.MESSAGE + ChatProtocol2.DM +"["
+ id + "(S)]" + data); //CHAT:[aaa(S)] 밥먹자=>bbb에게 넘어간다.
}else { //bbb가 접속이 안된 경우
sendMessage(ChatProtocol2.MESSAGE + ChatProtocol2.DM + "["
+ cmd + "]님 접속자가 아닙니다.");
}
}else if(cmd.equals(ChatProtocol2.CHATALL)) {
sendAllMessage(ChatProtocol2.CHATALL + ChatProtocol2.DM +"["
+ id + "]" + data);
}
else if(cmd.equals(ChatProtocol2.CHATALL)) {
sendAllMessage(ChatProtocol2.CHATALL + ChatProtocol2.DM +"["
+ id + "]" + data);
}
}
// client에게 메세지 전달 메서드
public void sendMessage(String msg) {
}
// 여기까지 ClientThread이다.
public static void main(String[] args) {
new ChatServer2();
}
}
코드 완성한 건 아니고 내일 수업 이어가면서 더 진행할 예정.