InetAddress 클래스

2022. 10. 7. 16:44Dev.Program/Java & Spring

728x90

======== JAVA0706

======== Ex.java

< InetAddress 클래스 >

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Ex {

public static void main(String[] args) {
/*
* InetAddress 클래스
* - 자바에서 IP 주소 관련 기능을 제공하는 클래스
*/

String url = "www.itwillbs.co.kr";

try {
// InetAddress 의 static 메서드인 getByName() 메서드를 사용하면
// 특정 URL 에 대한 IP 주소를 관리하는 InetAddress 객체를 가져올 수 있다!
InetAddress inetAddr = InetAddress.getByName(url);

// InetAddress 객체의 getXXX() 메서드를 호출하여 다양한 정보 가져오기
String hostName = inetAddr.getHostName(); // 대상 URL 의 호스트명
String hostAddress = inetAddr.getHostAddress(); // 대상 URL 의 서버 IP 주소
System.out.println(hostName + ", " + hostAddress);


} catch (UnknownHostException e) {
// 파라미터로 전달된 호스트 주소(도메인 포함)가 잘못됐을 경우 예외 발생
e.printStackTrace();
}

}

}

 

// 2. 자신의 로컬 호스트(localhost)에 대한 정보 가져오기
// => 로컬호스트 : 현재 어플리케이션이 동작 중인 호스트(=자기 자신)
InetAddress localhost = InetAddress.getLocalHost();
String localhostName = localhost.getHostName();
String localhostAddress = localhost.getHostAddress();
System.out.println(localhostName + ", " + localhostAddress);
  • 우리는 지금 VirtualBox 를 사용중이라 이렇게 가져옴

 

// 리턴받은 IP 주소를 옥텟(.) 기준으로 분리하여 배열에 저장
// ex) 192.168.1.200 => 0번 : 192, 1번 : 168, 2번 : 1, 3번 : 200 저장
// => String 클래스의 split() 메서드 필요
// => 단, 구분자가 마침표(.)일 경우 반드시 "\\." 형식으로 지정해야함
//    만약, 마침표만 기정할 경우 모든 문자를 구분자로 각각 사용함
String[] strIp = localhostAddress.split("\\.");
for(String IpArr : strIp) {
System.out.println(IpArr);
}

 

int[] ipArr = new int[4];
for(int i = 0; i < strIp.length; i++) {
ipArr[i] = Integer.parseInt(strIp[i]);
System.out.println(ipArr[i]);
}

 

// getAddress() 메서드를 사용하면 주소를 정수형으로 변환 가능
// ⇒ 단, byte[] 배열 타입으로 리턴되므로
//    IP 주소 옥텟 범위가 0 ~ 255 이지만, 일부가 음수값을 갖게 됨
//    즉, 실제 사용하는 IP 주소 숫자 범위와 다른 값을 갖는다! ⇒ 변환필요
byte[] b = localhost.getAddress();
for(byte bb : b) {
System.out.println(bb);
}

 

// getAddress() 메서드를 사용하면 주소를 정수형으로 변환 가능
// => 단, byte[] 배열 타입으로 리턴되므로
//    IP 주소 옥텟 범위가 0 ~ 255 이지만, 일부가 음수값을 갖게 됨
//    즉, 실제 사용하는 IP 주소 숫자 범위와 다른 값을 갖는다! => 변환 필요
byte[] b = localhost.getAddress();
for(byte bb : b) {
// System.out.println(bb);
// 저장된 byte[] 배열 내의 값은 -128 ~ +127 사이이므로
// IP 주소의 128 ~ 255 사이의 값이 음수로 저장되어 있음
// (0 ~ 127 까지의 값은 그대로 저장되어 있음)
// => 128 ~ 255 사이의 값을 만들려면 0보다 작은 값 + 256
System.out.println(bb < 0 ? bb + 256 : bb);

}



======== Ex2.java

  • 마우스 갖다대면 2번째 거 클릭해서 try~catch 추가

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;

public class Ex2 {

public static void main(String[] args) {
/*
* URL 클래스
* - URL : Uniform Resource Locator
* - URL 정보를 객체로 관리하는 클래스
*   => 파일, 디렉토리, DB의 Query 등 다양한 형식의 객체 관리
*/
BufferedReader buffer = null;

try {
// 특정 URL 정보를 객체로 관리하기 위해 URL 인스턴스 생성 시 URL 주소 전달
URL url = new URL("http://www.itwillbs.co.kr");

// 대상 URL 로부터 전달되는 데이터를 byte 타입으로 관리하기 위해
// InputStream 타입 객체로 리턴받음(해당 주소의 웹페이지 정보 전달됨)
// InputStream is = url.openStream();

// 정보에 대한 처리 방식을 byte -> char 단위로 변경하기 위해
// InputStream -> InputStreamReader 객체로 변환
// InputStreamReader reader = new InputStreamReader(is);

// 전달된 모든 문자들을 문자열 단위로 처리하기 위해
// InputStreamReader -> BufferedReader 객체로 변환
// BufferedReader buffer = new BufferedReader(reader);

// 위의 세 문장을 한 문장으로 결합할 경우
buffer = new BufferedReader(new InputStreamReader(url.openStream()));

String str = buffer.readLine();

while(str != null) { // 읽어온 문자열이 null(Ctrl + Z) 인지 판별
System.out.println(str);
str = buffer.readLine();
}

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
buffer.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}

}

  • 자바코드로 간단하게 크롤링해봄!~ (무식하게 다 긁어오는거)

 

// URL 객체에 대한 메타 데이터 정보 가져오기
url = new URL("http://www.google.co.kr/index.html");

System.out.println("프로토콜 : " + url.getProtocol());
System.out.println("포트번호 : " + url.getDefaultPort());
System.out.println("호스트명 : " + url.getHost());
System.out.println("파일명 : " + url.getFile());
  • getXXX() 메서드로 다양한 정보들을 가져올 수 있다

 

======== Ex3.java

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class Ex3 {

public static void main(String[] args) {
/*
* URLConnection 클래스
* - 대상 URL 객체와 어플리케이션에 대한 연결(통신)을 담당하는 클래스
* - 주로, 원격지 자원에 대한 속성 정보, 대상 파일에 대한 정보 읽기 등 지원
*/

try {
URL url = new URL("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png");

// URLConnection 객체를 얻기 위해 URL 객체의 openConnection() 메서드 호출
URLConnection con = url.openConnection();

// URLConnection 객체의 connect() 메서드를 호출하여 해당 URL 에 접속
con.connect();

System.out.println("대상 자원의 타입 : " + con.getContentType());
System.out.println(
"대상 자원(파일) 크기 : " + con.getContentLength() + " Byte");
System.out.println("대상 자원 최종 수정일 : " + con.getLastModified());

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

}

 

System.out.println("대상 자원 최종 수정일 : " + new Date(con.getLastModified()));

 

======== Ex4.java

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

public class Ex4 {

public static void main(String[] args) {
/*
* URLEncoder & URLDecoder 클래스
* - 문자열을 "x-www-urlencoded" 형식(MIME 형식)으로 변환하여 사용하는 클래스
* - URLEncoder 클래스는 기본 문자열 -> 인코딩 된 문자열로 변환
*   => URLEncoder.encode() 메서드 사용
* - URLDecoder 클래스는 인코딩 된 문자열 -> 기본 문자열로 변환
*   => URLDecoder.decode() 메서드 사용
*
* < URL 에 사용되는 문자열 변환 규칙 >
* 1. 아스키코드 문자(A ~ Z, a ~ z, 0 ~ 9) 는 그대로 변환됨
* 2. 공백 문자는 + 기호로 변환
* 3. 특수문자는 경우에 따라 변환되거나 변환되지 않음
* 4. 기타 문자(한글, 한자 등)는 % 기호 뒤에 16진수 2자리로 변환
*
*/


try {
String originalStr = "[ITWILL Java : 자바 프로그래밍 1]";

// URLEncoder 클래스의 encode() 메서드를 사용하여 원본 문자열을 인코딩
// => URLEncoder.encode(원본문자열, "인코딩방식");
String encodingStr = URLEncoder.encode(originalStr, "UTF-8");
System.out.println(encodingStr);
// %5BITWILL+Java+%3A+%EC%9E%90%EB%B0%94+%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D+1%5D

// URLDecoder 클래스의 decode() 메서드를 사용하여 인코딩 된 문자열을 복구
// => URLDecoder.decode(인코딩 된 문자열, "인코딩방식");
String decodingStr = URLDecoder.decode(encodingStr, "UTF-8");
System.out.println(decodingStr);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

}

}



======== Server.java

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

public static void main(String[] args) {
/*
* 소켓 프로그래밍(Socket Programming)
* - 통신을 하기 위해 사용되는 포트를 소켓(Socket)이라고 함
* - 소켓을 사용하여 원격 호스트와의 I/O 통신 상태를 구축
*   => Socket 클래스 활용
* - 서버측에서는 추가적으로 ServerSocket 클래스를 사용하여
*   클라이언트로부터의 요청을 받아들이는 작업 추가적으로 필요
*/

// Socket socket = null;
ServerSocket serverSocket = null;

try {
// ServerSocket 객체를 생성하면서, 포트번호를 파라미터로 전달하여
// 해당 포트를 소켓 통신용으로 오픈(클라이언트 접속을 위해 열어두기)
int port = 9999;
serverSocket = new ServerSocket(port);
// => 지정된 포트가 사용중일 경우 IOException 발생할 수 있음
} catch (IOException e) {
e.printStackTrace();
}

try {
while(true) {
// 클라이언트로부터 서버 접속 요청이 발생할 때까지 대기하다가
// 클라이언트로부터 요청이 발생하면 해당 요청을 받아서
// 상대 클라이언트와 소켓 연결 후 Socket 객체 리턴
Socket socket = serverSocket.accept();

// 연결된 클라이언트에게 메세지 전송
// 1. 상대방과 연결된 Socket 객체로부터 출력스트림 가져오기
OutputStream os = socket.getOutputStream();

// 2. 상대방에게 전달할 데이터를 스트림 객체로 생성
// => Object 타입으로 전달하기 위해 ObjectOutputStream 객체 생성
ObjectOutputStream oos = new ObjectOutputStream(os);

// 3. ObjectOutputStream 객체의 writeObject() 메서드를 호출하여
//    전달할 데이터(객체)를 생성하여 전달
String str = "Hello, World!";
oos.writeObject(str);
socket.close();
}

} catch (IOException e) {
e.printStackTrace();
}

}

}

 

======== Client.java

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

public static void main(String[] args) {
try {
// Socket 객체를 생성하여 접속할 서버 정보 입력 후 접속 수행
String host = "192.168.1.200"; // 접속할 서버의 IP 주소
int port = 9999; // 접속할 서버의 포트번호

Socket socket = new Socket(host, port); // 지정된 서버에 접속

// 서버로부터 수신된 데이터를 읽어오기 위해 InputStream 객체 가져오기
InputStream is = socket.getInputStream();

ObjectInputStream ois = new ObjectInputStream(is);

System.out.println("서버로부터 전달된 데이터 : " + ois.readObject());

ois.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
  • server.java 부터 실행하기
  • Client.java 에서 실행하면 이렇게 뜸



======== SimpleChatServer.java (JFrame 상속)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

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

public class SimpleChatServer extends JFrame {
JTextArea ta;
JTextField tf;

ServerSocket serverSocket;
Socket socket;

public SimpleChatServer() {
showFrame();
// service(); // 이렇게 호출도 가능
}

private void showFrame() {
setTitle("채팅 서버");
setBounds(400, 300, 400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 채팅 메세지 출력을 위한 JTextArea 생성 및 부착 - CENTER 영역 부착
ta = new JTextArea();
ta.setBackground(Color.LIGHT_GRAY); // 배경색 변경
ta.setEditable(false); // 입력 잠금 설정
add(ta, BorderLayout.CENTER);

// 채팅 메세지 입력을 위한 JTextField 생성 및 부착 - SOUTH 영역에 부착
tf = new JTextField();
add(tf, BorderLayout.SOUTH);

// JTextField 에 메세지 입력 후 엔터키 눌렀을 때 이벤트 처리
// => ActionListener 연결
tf.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
sendMsg();
}
});

setVisible(true);

// 화면 표시 후 메세지 입력 창에 커서 요청
tf.requestFocus();

// 채팅 서비스 시작을 위해 service() 메서드 호출
service();
}

// 채팅 서비스 동작을 위한 코드 기술
public void service() {
try {
ta.append("채팅 서비스 준비중...\n");

// 1. 채팅 서버를 열기 위한 ServerSocket 객체 생성 및 포트 번호 생성
int port = 9999;
serverSocket = new ServerSocket(port);

ta.append("클라이언트 접속 대기중...\n");
// 2. 클라이언트로부터 요청 대기 및 요청 시 소켓 연결 수행
socket = serverSocket.accept();

// 접속한 클라이언트 IP 주소 알아내기(Socket 객체의 getInetAddress())
ta.append("클라이언트가 접속했습니다. - " + socket.getInetAddress() + "\n");

socket.close();
serverSocket.close();

} catch (IOException e) {
e.printStackTrace();
}

}

// JTextField 에 메세지 입력 후 엔터키 입력 시 입력받은 메세지를 클라이언트에게 전송
public void sendMsg() {

}

public static void main(String[] args) {
new SimpleChatServer();

}

}



======== SimpleChatClient.java (JFrame 상속)

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

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

public class SimpleChatClient extends JFrame {
JTextArea ta;
JTextField tf;

Socket socket;

public SimpleChatClient() {
showFrame();
}

private void showFrame() {
setTitle("채팅 클라이언트");
setBounds(400, 300, 400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 채팅 메세지 출력을 위한 JTextArea 생성 및 부착 - CENTER 영역 부착
ta = new JTextArea();
ta.setBackground(Color.LIGHT_GRAY); // 배경색 변경
ta.setEditable(false); // 입력 잠금 설정
add(ta, BorderLayout.CENTER);

// 채팅 메세지 입력을 위한 JTextField 생성 및 부착 - SOUTH 영역에 부착
tf = new JTextField();
add(tf, BorderLayout.SOUTH);

// JTextField 에 메세지 입력 후 엔터키 눌렀을 때 이벤트 처리
// => ActionListener 연결
tf.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
sendMsg();
}
});
setVisible(true);

// 접속할 서버의 IP 주소 입력을 위한 다이얼로그 생성
String ip = JOptionPane.showInputDialog(this, "접속할 서버 IP 주소 입력");

if(ip == null || ip.equals("")) {
JOptionPane.showMessageDialog(this, "IP 주소 입력 필수!");
return;
}

// 화면 표시 후 메세지 입력 창에 커서 요청
tf.requestFocus();

service(ip);
}

public void service(String ip) {
try {
// 서버 접속을 위한 Socket 객체 생성
int port = 9999;
socket = new Socket(ip, port);
ta.append("서버 접속 완료. \n");

socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

// JTextField 에 메세지 입력 후 엔터키 입력 시 입력받은 메세지를 클라이언트에게 전송
public void sendMsg() {

}

public static void main(String[] args) {
new SimpleChatClient();

}

}



  • 서버부터 실행

  • 클라이언트에서 자기 IP 주소 적어보기

  • 서버 창에 자기 아이피주소 뜨면 성공!

 

< SimpleChatServer.java >

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.ServerSocket;
import java.net.Socket;

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

public class SimpleChatServer extends JFrame {
JTextArea ta;
JTextField tf;

ServerSocket serverSocket;
Socket socket;

// 문자열로 된 메세지 송수신을 위한
// DataOutputStream, DataInputStream 변수 선언
DataOutputStream dos;
DataInputStream dis;

public SimpleChatServer() {
showFrame();
// service(); // 이렇게 호출도 가능
}

private void showFrame() {
setTitle("채팅 서버");
setBounds(400, 300, 400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 채팅 메세지 출력을 위한 JTextArea 생성 및 부착 - CENTER 영역 부착
ta = new JTextArea();
ta.setBackground(Color.LIGHT_GRAY); // 배경색 변경
ta.setEditable(false); // 입력 잠금 설정
add(ta, BorderLayout.CENTER);

// 채팅 메세지 입력을 위한 JTextField 생성 및 부착 - SOUTH 영역에 부착
tf = new JTextField();
add(tf, BorderLayout.SOUTH);

// JTextField 에 메세지 입력 후 엔터키 눌렀을 때 이벤트 처리
// => ActionListener 연결
tf.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
sendMsg();
}
});

setVisible(true);

// 화면 표시 후 메세지 입력 창에 커서 요청
tf.requestFocus();

// 채팅 서비스 시작을 위해 service() 메서드 호출
service();
}

// 채팅 서비스 동작을 위한 코드 기술
public void service() {
try {
ta.append("채팅 서비스 준비중...\n");

// 1. 채팅 서버를 열기 위한 ServerSocket 객체 생성 및 포트 번호 생성
int port = 9999;
serverSocket = new ServerSocket(port);

ta.append("클라이언트 접속 대기중...\n");
// 2. 클라이언트로부터 요청 대기 및 요청 시 소켓 연결 수행
socket = serverSocket.accept();

// 접속한 클라이언트 IP 주소 알아내기(Socket 객체의 getInetAddress())
ta.append("클라이언트가 접속했습니다. - " + socket.getInetAddress() + "\n");

// ---------------------------------------------------------
// 클라이언트에게 환영 메세지 전송
// 1. 출력스트림 가져와서 DataOutputStream 객체 생성
dos = new DataOutputStream(socket.getOutputStream());
// 2. DataOutputStream 객체의 writeUTF() 메서드 호출하여 문자열 데이터 전송
dos.writeUTF("서버 : 채팅 서버에 접속하신 것을 환영합니다!");
// ---------------------------------------------------------

dos.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}

}

// JTextField 에 메세지 입력 후 엔터키 입력 시 입력받은 메세지를 클라이언트에게 전송
public void sendMsg() {

}

public static void main(String[] args) {
new SimpleChatServer();

}

}

 

< SimpleChatClient.java >

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.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

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

public class SimpleChatClient extends JFrame {
JTextArea ta;
JTextField tf;

// 문자열로 된 메세지 송수신을 위한
// DataOutputStream, DataInputStream 변수 선언
DataOutputStream dos;
DataInputStream dis;

Socket socket;

public SimpleChatClient() {
showFrame();
}

private void showFrame() {
setTitle("채팅 클라이언트");
setBounds(400, 300, 400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 채팅 메세지 출력을 위한 JTextArea 생성 및 부착 - CENTER 영역 부착
ta = new JTextArea();
ta.setBackground(Color.LIGHT_GRAY); // 배경색 변경
ta.setEditable(false); // 입력 잠금 설정
add(ta, BorderLayout.CENTER);

// 채팅 메세지 입력을 위한 JTextField 생성 및 부착 - SOUTH 영역에 부착
tf = new JTextField();
add(tf, BorderLayout.SOUTH);

// JTextField 에 메세지 입력 후 엔터키 눌렀을 때 이벤트 처리
// => ActionListener 연결
tf.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
sendMsg();
}
});
setVisible(true);

// 접속할 서버의 IP 주소 입력을 위한 다이얼로그 생성
String ip = JOptionPane.showInputDialog(this, "접속할 서버 IP 주소 입력");

if(ip == null || ip.equals("")) {
JOptionPane.showMessageDialog(this, "IP 주소 입력 필수!");
return;
}

// 화면 표시 후 메세지 입력 창에 커서 요청
tf.requestFocus();

service(ip);
}

public void service(String ip) {
try {
// 서버 접속을 위한 Socket 객체 생성
int port = 9999;
socket = new Socket(ip, port);
ta.append("서버 접속 완료. \n");

// ---------------------------------------------------------
// 1. 입력스트림 가져와서 DataInputStream 객체 생성
dis = new DataInputStream(socket.getInputStream());
// 2. DataInputStream 객체의 readUTF() 메서드 호출하여 문자열 데이터 전송
String str = dis.readUTF();
// 3. JTextField 에 수신된 문자열 출력
ta.append(str + "\n");
// ---------------------------------------------------------

dis.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

// JTextField 에 메세지 입력 후 엔터키 입력 시 입력받은 메세지를 클라이언트에게 전송
public void sendMsg() {

}

public static void main(String[] args) {
new SimpleChatClient();

}

}
  • 똑같이 실행해보기




>>>>> + 멀티스레드(최종 코드)

< SimpleChatServer.java >

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.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

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

public class SimpleChatServer extends JFrame {
JTextArea ta;
JTextField tf;

ServerSocket serverSocket;
Socket socket;

// 문자열로 된 메세지 송수신을 위한
// DataOutputStream, DataInputStream 변수 선언
DataOutputStream dos;
DataInputStream dis;

boolean stopSignal;

public SimpleChatServer() {
showFrame();
// service(); // 이렇게 호출도 가능
}

private void showFrame() {
setTitle("채팅 서버");
setBounds(400, 300, 400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 채팅 메세지 출력을 위한 JTextArea 생성 및 부착 - CENTER 영역 부착
ta = new JTextArea();
ta.setBackground(Color.LIGHT_GRAY); // 배경색 변경
ta.setEditable(false); // 입력 잠금 설정
add(ta, BorderLayout.CENTER);

// 채팅 메세지 입력을 위한 JTextField 생성 및 부착 - SOUTH 영역에 부착
tf = new JTextField();
add(tf, BorderLayout.SOUTH);

// JTextField 에 메세지 입력 후 엔터키 눌렀을 때 이벤트 처리
// => ActionListener 연결
tf.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
sendMsg();
}
});

setVisible(true);

// 화면 표시 후 메세지 입력 창에 커서 요청
tf.requestFocus();

// 채팅 서비스 시작을 위해 service() 메서드 호출
service();
}

// 채팅 서비스 동작을 위한 코드 기술
public void service() {
try {
ta.append("채팅 서비스 준비중...\n");

// 1. 채팅 서버를 열기 위한 ServerSocket 객체 생성 및 포트 번호 생성
int port = 9999;
serverSocket = new ServerSocket(port);

ta.append("클라이언트 접속 대기중...\n");
// 2. 클라이언트로부터 요청 대기 및 요청 시 소켓 연결 수행
socket = serverSocket.accept();

// 접속한 클라이언트 IP 주소 알아내기(Socket 객체의 getInetAddress())
ta.append("클라이언트가 접속했습니다. - " + socket.getInetAddress() + "\n");

// ---------------------------------------------------------
// 1. 입력스트림, 출력스트림 가져와서 DataXXXStream 객체 생성
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());

// 클라이언트에게 환영 메세지 전송
dos.writeUTF("서버 : 채팅 서버에 접속하신 것을 환영합니다!");
Thread t = new Thread(new Runnable() {

@Override
public void run() {
try {
while(!stopSignal) { // 중지 신호가 올때까지 반복
// 2. DataInputStream 객체의 readUTF() 메서드 호출하여 문자열 데이터 전송
String str = dis.readUTF();
// 3. JTextField 에 수신된 문자열 출력
ta.append(str + "\n");
}
} catch (EOFException e) { // 접속이 끊어질 경우 발생하는 예외 처리
// e.printStackTrace();
System.out.println("클라이언트로부터 접속 끊어짐!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
dis.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});

// 멀티쓰레딩 실행을 위해 start() 메서드 호출
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}

// JTextField 에 메세지 입력 후 엔터키 입력 시 입력받은 메세지를 클라이언트에게 전송
public void sendMsg() {
try {
// JTextField 에 입력된 메세지를 가져오기
String msg = tf.getText();

// 입력된 메세지를 JTextArea 에 출력(내 채팅창에 표시)
ta.append(msg + "\n");

// 만약, 입력된 메세지(문자열)가 "/exit" 이면, "bye" 메세지 출력 후 종료
if(msg.equals("/exit")) {
ta.append("bye"); // 메세지 출력

// 현재 반복중인 수신 쓰레드에 종료 신호 전달
stopSignal = true;

// 출력스트림, 소켓 자원 반환
dos.close();
socket.close();
serverSocket.close();

// 현재 어플리케이션 종료
System.exit(0);;
} else { // 입력된 문자열이 "/exit" 가 아니면 클라이언트에게 메세지 전송
dos.writeUTF("서버 : " + msg);
// JTextField 입력창 초기화 및 커서 요청
tf.setText("");
tf.requestFocus();
}
} catch (IOException e) {
e.printStackTrace();
}

}

public static void main(String[] args) {
new SimpleChatServer();
}

}



< SimpleChatClient.java >

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.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

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

public class SimpleChatClient extends JFrame {
JTextArea ta;
JTextField tf;

// 문자열로 된 메세지 송수신을 위한
// DataOutputStream, DataInputStream 변수 선언
DataOutputStream dos;
DataInputStream dis;

boolean stopSignal; // 멀티쓰레딩 중지 신호를 저장할 변수

Socket socket;

public SimpleChatClient() {
showFrame();
}

private void showFrame() {
setTitle("채팅 클라이언트");
setBounds(400, 300, 400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// 채팅 메세지 출력을 위한 JTextArea 생성 및 부착 - CENTER 영역 부착
ta = new JTextArea();
ta.setBackground(Color.LIGHT_GRAY); // 배경색 변경
ta.setEditable(false); // 입력 잠금 설정
add(ta, BorderLayout.CENTER);

// 채팅 메세지 입력을 위한 JTextField 생성 및 부착 - SOUTH 영역에 부착
tf = new JTextField();
add(tf, BorderLayout.SOUTH);

// JTextField 에 메세지 입력 후 엔터키 눌렀을 때 이벤트 처리
// => ActionListener 연결
tf.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
sendMsg();
}
});
setVisible(true);

// 접속할 서버의 IP 주소 입력을 위한 다이얼로그 생성
String ip = JOptionPane.showInputDialog(this, "접속할 서버 IP 주소 입력");

if(ip == null || ip.equals("")) {
JOptionPane.showMessageDialog(this, "IP 주소 입력 필수!");
return;
}

// 화면 표시 후 메세지 입력 창에 커서 요청
tf.requestFocus();

service(ip);
}

public void service(String ip) {
try {
// 서버 접속을 위한 Socket 객체 생성
int port = 9999;
socket = new Socket(ip, port);
ta.append("서버 접속 완료. \n");

// ---------------------------------------------------------
// 1. 입력스트림, 출력스트림 가져와서 DataXXXStream 객체 생성
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());

// ---------------------------------------------------
// 서버로부터 전달받는 메세제 출력을 위한 멀티쓰레딩 구현
Thread t = new Thread(new Runnable() {

@Override
public void run() {
try {
while(!stopSignal) { // 중지 신호가 올때까지 반복
// 2. DataInputStream 객체의 readUTF() 메서드 호출하여 문자열 데이터 전송
String str = dis.readUTF();
// 3. JTextField 에 수신된 문자열 출력
ta.append(str + "\n");
}
} catch (EOFException e) { // 접속이 끊어질 경우 발생하는 예외 처리
// e.printStackTrace();
System.out.println("서버로부터 접속 끊어짐!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
dis.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});

// 멀티쓰레딩 실행을 위해 start() 메서드 호출
t.start();
// ---------------------------------------------------------

// dis.close();
// socket.close();

} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

// JTextField 에 메세지 입력 후 엔터키 입력 시 입력받은 메세지를 서버에게 전송
public void sendMsg() {
try {
// JTextField 에 입력된 메세지를 가져오기
String msg = tf.getText();

// 입력된 메세지를 JTextArea 에 출력(내 채팅창에 표시)
ta.append(msg + "\n");

// 만약, 입력된 메세지(문자열)가 "/exit" 이면, "bye" 메세지 출력 후 종료
if(msg.equals("/exit")) {
ta.append("bye"); // 메세지 출력

// 현재 반복중인 수신 쓰레드에 종료 신호 전달
stopSignal = true;

// 출력스트림, 소켓 자원 반환
dos.close();
socket.close();

// 현재 어플리케이션 종료
System.exit(0);;
} else { // 입력된 문자열이 "/exit" 가 아니면 서버에게 메세지 전송
dos.writeUTF("클라이언트 : " + msg);
// JTextField 입력창 초기화 및 커서 요청
tf.setText("");
tf.requestFocus();
}
} catch (IOException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
new SimpleChatClient();
}

}
  • 채팅창 쳐보면 서로 주고받는 거 확인할 수 있다!
  • 메세지 창에
    쳐보면
  • 콘솔창에서 확인가능

 

728x90

'Dev.Program > Java & Spring' 카테고리의 다른 글

[Spring] - (2)  (0) 2022.10.09
[Spring] - (1)설치 및 설정하기  (0) 2022.10.09
데이터 입출력 : IO(Input/Output)  (0) 2022.10.07
MVC2 - (5)  (0) 2022.10.07
MVC2 - (4)  (0) 2022.10.07