본문 바로가기

IT자격증공부방

Java simple serve client 예제

Java simple serve client 예제

 

//클라이언트

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.sound.midi.SysexMessage;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class SimpleClient extends Thread implements ActionListener {
JFrame jFrame;
JTextArea jta;
JTextField jtf;

Socket s1;

DataOutputStream dos;
DataInputStream dis;
boolean stop;

JDialog jDialog;
JTextField jtf2;  // IP 입력  15글자만 입력 가능
JLabel jLabel;  
String host;   //접속할 채팅 서버의 IP주소를 저장할 변수
String msg;

public SimpleClient() {
// TODO Auto-generated constructor stub
launchFrame();

}

private void launchFrame() {
jFrame = new JFrame("일대일 채팅 실습");
jta = new JTextArea();
jtf = new JTextField();
jFrame.setBackground(Color.LIGHT_GRAY);
jta.setEditable(false);
jFrame.add(jta,BorderLayout.CENTER);
jFrame.add(jtf, BorderLayout.SOUTH);

jtf.addActionListener(this);

jFrame.setSize(500,300);
jFrame.setVisible(true);
jtf.requestFocus();

jDialog = new JDialog(jFrame, "서버 IP", true);
jLabel = new JLabel("접속할 채팅 서버의 IP주소를 입력하세요.");
jtf2 = new JTextField(15); // 15글자만 입력 가능
jDialog.add(jLabel,BorderLayout.NORTH);
jDialog.add(jtf2,BorderLayout.CENTER);
jtf2.addActionListener(this);

jDialog.pack();  // Dialog 기본 사이즈
jDialog.setVisible(true);

//service메소드 호출!
// <1>클라이언트 전용 소켓 통로를 생성
//  <2>또한 접속한 서버프로그램으로부터 전달받은 메시지를 읽어들일 입력스트림통로 생성
// <3>접속한 서버프로그램에게 메시지를 전달할 출력스트림 통로 생성
//  <4>run메소드가 실행되도록 start메소드를 호출함
service();
//JDialog창 내부에 부착된 JTextField jtf2에 강제 포커스 주기(IP를 입력할 수 있도록!)
jtf2.requestFocus();
}
public void service() {
try {  //<1>클라이언트 프로그램에서 서버프로그램으로 통신을 하기 위해
//클라이언트 전용 소켓 통로 생성!
//방법 : 서버의 IP주소를 host변수값으로 전달하고,
// 서버의 port번호 5432를 전달하여 생성한다.

s1 = new Socket(host,5432);
//<2>입력스트림 통로
dis = new DataInputStream(s1.getInputStream());

//<3>출력스트림 통로
dos = new DataOutputStream(s1.getOutputStream());
//접속 완료를 나타내기 위해 프레임창 내부에 부착된 TextArea영역에 "접속 완료"메시지 
jta.append("접속 완료.\n");
//<4>stop변수가 true가 되면 서버에서 전송된 데이터를 읽는 작업을 하는 스레드 동작 시키기
//SimpleClient클래스 자체가 스레드를 상속받아서 클래스 자체가 스레드가 됨
this.start();

} catch (UnknownHostException e) {  // 주소(IP) 잘못 입력
// TODO: handle exception
e.printStackTrace();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}

//<1>JTextField 2개
//첫번째 jtf -> JFrame창에 부착된 필드 영역
//두번째 jtf2 -> JDialog창에 부착된 필드 영역
//<2>입력한 메시지를 출력스트림을 통해 서버프로그램으로 보내기

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(jtf == e.getSource()) {
//발생한 이벤트가 발생한 소스가 JFrame창에 부착된 JTextField라면?
//여기서 발생한 이벤트는 텍스트필드에 뭔가가 입력된 행위를 의미함
msg = jtf.getText();
// 채팅 메세지 입력 후 엔터키를 누르고 나면 JTextField에 입력됐던 텍스트를 없애서
// (공백을 입력해서) 다른 텍스트를 입력할 수 있도록 하기
jtf.setText("");
jta.append(msg+"\n");
try {
if(msg.equals("exit")) { //채팅창(JTextField)에 "exit" 입력되면?
//JTextArea영역에 "Bye" 출력하고
jta.append("Bye");
//stop변수의 값을 false ->true로 변경해줌
stop = true;
//마지막으로 자원해제 해주고, 프로그램 종료
//출력스트림 닫기
dos.close();
//클라이언트 전용 소켓 닫기
s1.close();
System.exit(0);
} else {  //채팅창(JTextField)에 exit가 아닌 다른 텍스트를 입력했다면?
//서버프로그램 프레임창에 입력한 텍스트 메시지를 스트림을 통해 보낸다.
dos.writeUTF("클라이언트 : "+ msg);
}


} catch (IOException e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
// 발생한 이벤트가 발생한 소스가 JFrame창에 부착된 JTextField가 아니라면? 
// => JDialog창에 발생한 이벤트라면?
//접속할 채팅서버의 IP주소를 입력받아 저장
else if(jtf2 == e.getSource()) {
//다이얼로그창에 부착된 JTextField에 입력한 문자열을 얻고,
// trim()을 통해 혹시나 입력됐을 공백이 있으면 삭제하여 반환받아 host변수에 저장
host = jtf2.getText().trim();
if(host == "") {
host = "localhost";
//또는 "127.0.0.1" 또는 실제 IP주소를 확인하여 host에 저장한다.
//참고! 
//★★자기 자신 컴퓨터의 IP주소는 "localhost"혹은 "127.0.0.1"이다.★★
} //if 끝
jDialog.dispose();
}  // else if 끝 
}  // actionPerformed 끝


//서버프로그램에서 보내온 메시지를 읽어들여 JTextArea영역에 출력하는 작업
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Thread started.......");
try {

 while(!stop) {
//서버프로그램이 보낸 메시지를 읽어서 
 String message = dis.readUTF();
//클라이언트 채팅프로그램의 JTextArea영역에 보여준다.
 jta.append(message);
 } //반복문 끝
  //stop변수에 저장되는 값이 false일 때
//입력스트림 통로 자원해제
 dis.close();
//클라이언트 전용 소켓 자원해제
 s1.close();

} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}

public static void main(String[] args) {
// TODO Auto-generated method stub
new SimpleClient();
}

}

 

// 서버

 

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;

//1. main스레드
// 역할1. 프레임창 만들기
// 역할2. 서버소켓통로를 만들어 클라이언트의 요청을 대기

//2. SimpleServer스레드
// 역할1. 서버프로그램에서 클라이언트프로그램으로 메시지 송수신

public class SimpleServer extends Thread implements ActionListener{

JFrame jframe;
JTextArea jta;  //채팅 출력 공간
JTextField jtf; //채팅 입력공간
//서버용 소켓통로 객체를 생성해서 저장할 변수
ServerSocket s;
Socket s1;
//클라이언트 채팅프로그램 측으로 메시지를 보내되..
//OutputStream통로는 메시지를 1바이트 단위로 보내기 때문에..
//조금 더 편하게 여러 바이트를 기본 자료형(int, double, float, ...)
//의 바이트 크기로 묶어서 
//메시지를 보내줄 수 있는 DataOutputStream통로 객체를 생성해서 저장할 변수 선언
DataOutputStream dos;
DataInputStream dis;
//클라이언트 프로그램에서 전송된 메시지를 읽어들이기 위한 조건 변수
//stop이 false 상태여야 데이터를 읽어들임
boolean stop;  //기본값이 false로 저장되어 있는 상태임

public SimpleServer() {
// TODO Auto-generated constructor stub
try {
launchFrame();// 디자인 창 역활
service();// 통신 역활
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}

}

public void launchFrame() {
//JFrame클래스 객체를 생성하여 프레임창 하나 만들기
//프레임창 만들때 창제목 설정
jframe = new JFrame("일대일 채팅 실습");

//JTextArea클래스 객체를 생성(JTextField입력공간에서 입력한 메시지를 보여주기 위함)
jta = new JTextArea();

//JTextField클래스 객체 생성(메시지를 입력하는 공간을 만들기 위한 영역이다.)
jtf = new JTextField();

//JFrame창 배경색을 지정
jframe.setBackground(Color.LIGHT_GRAY);

//JTextArea(채팅 내용 보여주는 공간) 비활성화(데이터를 입력할 수 없도록 막기)
jta.setEditable(false);//false는 비활성화, true는 활성화

//JFrame창에 JTextArea와 JTextField 배치
jframe.add(jta, BorderLayout.CENTER);
jframe.add(jtf,BorderLayout.SOUTH);

//**JTextField 영역에서 텍스트를 입력하면 액션이벤트가 발생하므로
//Action이벤트 처리할 리스너 객체를 JTextfield에 등록************
jtf.addActionListener(this);
    //this는 SimpleServer클래스(액션리스너 인터페이스 상속)받으므로 
    // SimpleServer클래스 자체가 액션리스너가 된다.
jframe.setSize(500, 300);
jframe.setVisible(true);

//JTextField 입력 공간에 강제로 포커스 주기
jtf.requestFocus();

}
//서버소켓통료 생성하고, 클라이언트의 요청 기다리기
//클라이언트 프로그램에서 서버프로그램으로 접속요청을 보내면
//새로운 클라이언트용 소켓통로를 생성하여
//그 소켓통로를 통해 입출력 스트림 통로를 만든다.
//그리고 실제로 채팅 메시지를 주고 받을 스레드에게 일을 시킨다.
public void service() throws Exception {
//jta에 문자열 보내줌(추가),,\n해줘야 한줄 띄우고 받아온 채팅메시지 출력함
jta.append("서비스를 하기 위해 준비중....\n");
//서버소켓 통로 생성
s = new ServerSocket(5432); //<-포트번호 입력,, ip주소는 자동으로 부여됨 
jta.setText("클라이언트 접속 대기중");
//append메소드는 문자열 추가, setText는 문자열 덮어씀

//ServerSocket객체의 accept()메소드를 이용하여
//클라이언트의 요청을 기다리면서 대기한다.
//ServerSocket통로로부터 현재 접속한 사용자(클라이언)의 정보를 가지고 있는
//클라이언트용! Socket통로 객체를 리턴받는다.
s1 = s.accept();
//서버프로그램에 접속한 클라이언트 ip주소 정보 JTextArea영역에 보여주기
jta.append("클라이언트가 접속하였습니다. : "+s1.getInetAddress()+"\n");

//서버프로그램에 접속한 클라이언트에게 메시지를 보내기 위한 출력스트림 통로 생성
dos = new DataOutputStream((s1.getOutputStream()));//1바이트 단위로 내보낼 통로
//접속한 클라이언트프로그램에서 보내온 메시지를 읽어들이기 위한 입력스트림 통로 생성
dis = new DataInputStream((s1.getInputStream()));

//**실제로 채팅 메시지 주고 받는 작업을 하는 스레드 시작!***********************
this.start();//this는 SimpleServer클래스의 객체 주소값을 가짐,, run()메소드 실행됨!!
//접속한 클라이언트 프로그램의 프레임창에 부착된 JTextArea 영역에
//채팅 서버프로그램에 접속을 알리기 위해 메시지를 보냄
dos.writeUTF("채팅 서버에 접속하신걸 환영합니다.\n");
//writeUTF()는 문자열 단위로 한번에 보낼 수 있는 메소드

}



@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//이벤트 처리 
// : JTextField에 입력한 메시지 얻어 JTextArea영역에 보여주기

try {
//JTextField에 입력한 텍스트를 얻어 msg변수에 저장
String msg = jtf.getText();
//얻은 텍스트를 JTextArea영역에 보내어 출력되게 한다
jta.append(msg+"\n");

//JTextFiedl에서 입력한 채팅(문자열)을 전송하고 나서는
//JTextField 영역에 텍스트를 없애기 위해 대신~ 빈 공백 문자열을 넣어준다.(덮어쓰자)
jtf.setText(" ");

//접속한 클라이언트 프로그램이 서버프로그램에 의해서 강제 종료
if(msg.equals("exit")) {
jta.append("Bye");
//stop변수에 저장된 false 기본값을 true로 변경(설정)
stop = true; //클라이언트 채팅프로그램이 보낸 채팅(문자열)을 못 읽어들이게 하는 조건변수
//접속한 클라이언트 프로그램이 서버프로그램에 의해서 강제 종료될 수 있도록 하자
// (모든 통로를 닫아야 함.)
dos.close();//통신 끊김
s1.close();
System.exit(0);  //정상종료 0, 비정상 종료 1
} else {
//다른 문자열을 입력했다면?
//채팅서버프로그램 창에 입력한 메시지를 
//채팅클라이언트 프로그램 창(JTextArea)에 내보내어 출력되게 해야 한다.
dos.writeUTF("채팅서버 : " +msg +"\n");
}

} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}



}

//  채팅서버 프로그램에 입력한 메시지를 클라이언트 프로그램에 출력스트림 통로로 보내기
@Override
public void run() {
// 채팅 메시지 주고받는 작업 -> stop변수에 저장되는 값이 true가 
// 될때까지 클라이언트가 전송한 데이터를 읽어들인다.
// service()메소드 내의 this.start() 해주면 run메소드 실행됨!
// 따라서 stop변수가 true로 변경됨!
// TODO Auto-generated method stub
try {
while(!stop) {
//stop변수에 저장되는 값이 false일 때 반복,,run메소드 실행되면 !
// stop은 false..?
//채팅 클라이언트 프로그램에서 보낸 메시지를 읽어들여서
//채팅 서버 프로그램의 JTextArea영역에 보내어 출력
jta.append(dis.readUTF()+"\n");

}
//stop변수가 true가 되면
//접속한 클라이언트로부터 메시지를 전달받아 읽어들일 입력 스트림 통로 닫기
dis.close();
//클라이언트 전용 소켓 닫기
s1.close();

} catch (EOFException e) {
// TODO: handle exception
jta.append("클라이언트로부터 연결이 끊어졌습니다.");
e.printStackTrace();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}

public static void main(String[] args) {
// TODO Auto-generated method stub
new SimpleServer();


}

}