일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 자바의 정석 기초편 ch11
- 자바의 정석 기초편 ch2
- 스프링 mvc2 - 로그인 처리
- 스프링 mvc1 - 스프링 mvc
- 자바의 정석 기초편 ch7
- 스프링 mvc2 - 검증
- 자바의 정석 기초편 ch6
- 자바 고급2편 - io
- 자바로 계산기 만들기
- 데이터 접근 기술
- 2024 정보처리기사 수제비 실기
- 스프링 트랜잭션
- 자바의 정석 기초편 ch13
- 자바의 정석 기초편 ch4
- 자바의 정석 기초편 ch5
- 자바 중급1편 - 날짜와 시간
- 자바의 정석 기초편 ch9
- 자바 중급2편 - 컬렉션 프레임워크
- @Aspect
- 스프링 입문(무료)
- 스프링 고급 - 스프링 aop
- 자바의 정석 기초편 ch14
- 자바의 정석 기초편 ch1
- 람다
- 자바 고급2편 - 네트워크 프로그램
- 스프링 mvc2 - 타임리프
- 자바로 키오스크 만들기
- 2024 정보처리기사 시나공 필기
- 자바 기초
- 자바의 정석 기초편 ch12
- Today
- Total
개발공부기록
Chapter19 - 네트워크 입출력, IP 주소 얻기, TCP 네트워킹, UDP 네트워킹 본문
Chapter19 - 네트워크 입출력, IP 주소 얻기, TCP 네트워킹, UDP 네트워킹
소소한나구리 2025. 2. 11. 23:361. IP 주소 얻기
자바는 IP 주소를 java.net 패키지의 InetAddress로 표현함
InetAddress를 이용하면 로컬 컴퓨터의 IP 주소를 얻을 수 있고, 도메인 이름으로 DNS에서 검색한 후 IP 주소를 가져올 수도 있음
InetAddress.getLocalHost(): 로컬 컴퓨터의 InetAddress를 얻을 수 있음
InetAddress.getByName(String domainName): 도메인 이름으로 등록된 단 하나의 IP 주소를 가져옴
InetAddress.getAllByName(String domainName): 등록된 모든 IP 주소를 배열로 가져옴
리턴값은 문자열로 된 IP 주소임
하나의 도메인 이름으로 여러 IP가 등록되어 있는 이유는 클라이언트가 많이 연결되었을 경우 서버 부하를 나누기 위해서임
InetAddressExample
package chapter19.sec02;
public class InetAddressExample {
public static void main(String[] args) {
try {
InetAddress local = InetAddress.getLocalHost();
System.out.println("내 컴퓨터 IP 주소: " + local.getHostAddress());
InetAddress[] iaArr = InetAddress.getAllByName("www.naver.com");
for (InetAddress remote : iaArr) {
System.out.println("www.naver.com IP 주소: " + remote.getHostAddress());
}
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}
/* 실행 결과
내 컴퓨터 IP 주소: 127.0.0.1
www.naver.com IP 주소: 223.130.200.236
www.naver.com IP 주소: 223.130.200.219
www.naver.com IP 주소: 223.130.192.248
www.naver.com IP 주소: 223.130.192.247
*/
2. TCP 네트워킹
IP 주소로 프로그램들이 통신할 때는 약속된 데이터 전송 규약이 있는데 이것을 전송용 프로토콜이라고 부르며 인터넷에서 전송용 프로토콜은 TCP와 UDP가 있음
TCP
연결형 프로토콜로 상대방이 연결된 상태에서 데이터를 주고받으며 클라이언트가 연결 요청을 하고 서버가 연결을 수락하면 통신 회선이 고정되고 데이터는 고정 회선을 통해 전달되기 때문에 TCP는 보낸 데이터가 순서대로 전달되며 손실이 발생하지 않음
IP와 함께 사용하기 때문에 TCP/IP라고도 함
자바는 TCP 네트워킹을 위해 java.net 패키지에서 ServerSocket과 Socket 클래스를 제공하고 있으며 ServerSocket은 클라이언트의 연결을 수락하는 서버 쪽 클래스이고 Socket은 클라이언트에서 연결 요청할 때와 클라이언트와 서버 양쪽에서 데이터를 주고받을 때 사용되는 클래스임
ServerSocket을 생성할 때는 바인딩할 Port 번호를 지정해야하며 서버가 실행되면 클라이언트는 Socket을 이용해서 서버의 IP주소와 Port번호로 연결 요청을 할 수 있음
ServerSocket은 accept() 메소드로 연결을 수락하고 통신용 Socket을 생성하고 나서 클라이언트와 서버는 양쪽의 Socket을 이용해서 데이터를 주고받게 됨
TCP 서버
TCP 서버 프로그램을 개발하려면 우선 ServerSocket 객체를 생성해야하는데 객체를 생성할 때 인자로 포트번호를 넘겨주거나, 먼저 기본 생성자로 객체를 생성하고 Port 바인딩을 위해 bind() 메서드를 호출하면 됨
ServerSocket serversocket = new ServerSocket(50001);
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(50001));
만약 서버 컴퓨터에 여러 개의 IP가 할당되어 있을 경우 특정 IP에서만 서비스를 하고 싶다면 InetSocketAddress의 첫 번째 매개값으로 해당 IP를 주면됨
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("xxx.xxx.xxx.xxx", 50001));
만약 Port가 이미 다른 프로그램에서 사용 중이라면 BindException이 발생하며 이 경우에는 다른 Port로 바인딩하거나 Port를 사용 중인 프로그램을 종료하고 다시 실행하면 됨
ServerSocket이 생성되었으면 연결 요청을 수락하기 위해 accept() 메서드를 실행해야 함
accept()는 클라이언트가 연결 요청하기 전까지 블로킹이 되며 클라이언트의 연결 요청이 들어오면 블로킹이 해제되고 통신용 Socket을 리턴함
Socket socket = serverSocket.accept();
만약 리턴된 Socket을 통해 연결된 클라이언트의 IP 주소와 Port 번호를 얻고 싶다면 getRemoteSocketAddress() 메서드를 호출해서 InetSocketAddress를 얻은 다음 getHostName()과 getPort() 메소드를 호출하면 됨
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
String clientIp = isa.getHostName();
String portNo = isa.getPort();
서버를 종료하려면 ServerSocket의 close() 메소드를 호출해서 Port 번호를 언바인딩 시켜야 다른 프로그램에서 해당 Port 번호를 재사용할 수 있음
serverSocket.close();
ServerExample
package chapter19.sec03;
public class ServerExample {
private static ServerSocket serverSocket = null;
public static void main(String[] args) {
System.out.println("------------------------------------------------");
System.out.println("서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.");
System.out.println("------------------------------------------------");
// TCP 서버 시작
startServer();
// 키보드 입력
Scanner scanner = new Scanner(System.in);
while (true) {
String key = scanner.nextLine();
if (key.toLowerCase().equals("q")) {
break;
}
}
scanner.close();
// TCP 서버 종료
stopServer();
}
private static void startServer() {
// 작업 스레드 정의 Thread -> Runnable로 변경
Runnable runnable = () -> {
try {
serverSocket = new ServerSocket(50001);
System.out.println("[서버] 시작됨");
while (true) {
System.out.println("\n[서버] 연결 요청을 기다림\n");
// 연결 수락
Socket socket = serverSocket.accept();
// 연결된 클라이언트 정보 얻기
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");
// 연결 끊기
socket.close();
System.out.println("[서버] " + isa.getHostName() + ":" + isa.getPort() + "의 연결을 끊음");
}
} catch (IOException e) {
System.out.println("[서버] " + e.getMessage());
}
};
new Thread(runnable).start();
}
private static void stopServer() {
try {
serverSocket.close();
System.out.println("[서버] 종료됨");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
TCP 클라이언트
클라이언트가 서버에 연결 요청을 하려면 Socket 객체를 생성할 때 생성자 매개값으로 서버 IP 주소와 Port번호를 제공하면 됨
로컬 컴퓨터에서 실행하는 서버로 연결 요청을 할 경우에는 IP 주소대신 localhost를 사용할 수 있음
만약 IP 주소 대신 도메인 이름을 사용하고 싶다면 DNS에서 IP 주소를 검색할 수 있도록 생성자의 매개값으로 InetAddress를 제공해야 함
Socket 생성과 동시에 연결 요청을 하지 않고 기본 생성자로 Socket을 생성한 후 connect() 메서드로 연결 요청을 할 수도 있음
Socket socket = new Socket("IP", 50001);
Socket socket = new Socket(InetAddress.getByName("domainName", 50001);
Socket socket = new Socket();
socket.connect(new InetAddress.getByName("domainName", 50001);
연결 요청 시 두 가지 예외가 발생할 수 있는데 UnknownHostException은 Ip 주소가 잘못 표기되었을 때 발생하고 IOException은 제공된 IP와 Port 번호로 연결할 수 없을 때 발생하므로 두 가지 예외를 모두 처리해야 함
서버와 연결된 후에 클라이언트에서 연결을 끊고 싶다면 close() 메서드를 호출하면 됨
ClientExample
package chapter19.sec03;
public class ClientExample {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 50001);
System.out.println("[클라이언트] 연결 성공");
// Socket 닫기
socket.close();
System.out.println("[클라이언트] 연결 끊음");
} catch (UnknownHostException e) {
// IP 표기 방법이 잘못 되었을 경우
} catch (IOException e) {
// 해당 포트의 서버에 연결할 수 없는 경우
}
}
}
ServerExample 실행 후 ClientExample 실행 결과
------------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.
------------------------------------------------
[서버] 시작됨
[서버] 연결 요청을 기다림
[서버] localhost의 연결 요청을 수락함
[서버] localhost:52456의 연결을 끊음
[서버] 연결 요청을 기다림
입출력 스트림으로 데이터 주고받기
클라이언트가 연결 요청을 하고 서버가 연결 수락을 했다면 양쪽의 Socket 객체로부터 각각 입력 스트림과 출력 스트림을 얻을 수 있음
다음 코드로 InputStream과 OutputStream을 얻을 수 있음
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
상대방에게 데이터를 보낼 때에는 보낼 데이터를 byte[] 배열로 생성하고 이것을 매개값으로 해서 OutputStream의 write() 메서드를 호출하면 됨
다음 코드는 문자열로부터 UTF-8로 인코딩한 바이트 배열을 얻어내고 write() 메서드로 전송함
String data = "보낼 데이터";
byte[] bytes = data.getBytes("UTF-8");
OutputStream os = socket.getOutputStream();
os.write(bytes);
os.flush();
문자열을 좀 더 간편하게 보내고 싶다면 보조 스트림인 DataOutputStream을 연결해서 사용하면 됨
String data = "보낼 데이터"
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(data);
dos.flush();
데이터를 받기 위해서는 받은 데이터를 저장할 byte[] 배열을 하나 생성하고 이것을 매개값으로 해서 InputStream의 read() 메서드를 호출하면 됨
read() 메서드는 읽은 데이터를 byte[] 배열에 저장하고 읽은 바이트 수를 리턴함
받는 데이터가 문자열이라면 byte[]배열을 UTF-8로 디코딩해서 문자열로 얻을 수 있음
byte[] bytes = new byte[1024];
InputStream is = socket.getInputStream();
int num = is.read(bytes);
String data = new String(bytes, 0, num, "UTF-8");
문자열을 좀 더 간편하게 받고 싶다면 보조 스트림인 DataInputStream을 연결해서 사용하면 되지만 이 방법은 상대방이 DataOutputStream으로 문자열을 보낼 때만 가능함
DataInputStream dis = new DataInputStream(socket.getInputStream());
String data = dis.readUTF();
EchoServer
TCP 클라이언트가 보낸 메시지를 다시 돌려보내는 에코 TCP 서버를 구현한 예제
package chapter19.sec03.exam02;
public class EchoServer {
private static ServerSocket serverSocket;
public static void main(String[] args) {
System.out.println("------------------------------------------------");
System.out.println("서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.");
System.out.println("------------------------------------------------");
startServer(); // TCP 서버 시작
// 키보드 입력
Scanner scanner = new Scanner(System.in);
while(true) {
String key = scanner.nextLine();
if (key.toLowerCase().equals("q")) {
break;
}
}
scanner.close();
stopServer();
}
public static void startServer() {
// 작업 스레드 정의
Thread thread = new Thread() {
@Override
public void run() {
try {
// ServerSocket 생성 및 Port 바인딩
serverSocket = new ServerSocket(50001);
System.out.println("[서버] 시작됨");
// 연결 수락 및 데이터 통신
while (true) {
System.out.println("\n[서버] 연결 요청을 기다림\n");
// 연결 수락
Socket socket = serverSocket.accept();
// 연결된 클라이언트 정보 얻기
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");
/*
// 데이터 받기1
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int readByteCount = is.read(bytes);
String message = new String(bytes, 0, readByteCount, "UTF-8");
// 데이터 보내기
OutputStream os = socket.getOutputStream();
bytes = message.getBytes("UTF-8");
os.write(bytes);
os.flush();
System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);
*/
// 데이터 받기2
DataInputStream dis = new DataInputStream(socket.getInputStream());
String message = dis.readUTF();
// 데이터 보내기2
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(message);
dos.flush();
System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);
// 연결 끊기
socket.close();
System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음");
}
} catch (IOException e) {
System.out.println("[서버] " + e.getMessage());
}
}
};
thread.start();
}
private static void stopServer() {
try {
serverSocket.close();
System.out.println("[서버] 종료됨");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
EchoClient
package chapter19.sec03.exam02;
public class EchoClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 50001);
System.out.println("[클라이언트] 연결 성공");
/*
// 데이터 보내기1
String sendMessage = "이것이 자바다 TCP 전송";
OutputStream os = socket.getOutputStream();
byte[] bytes = sendMessage.getBytes("UTF-8");
os.write(bytes);
os.flush();
System.out.println("[클라이언트] 데이터 보냄: " + sendMessage);
// 데이터 받기1
InputStream is = socket.getInputStream();
bytes = new byte[1024];
int readByteCount = is.read(bytes);
String receiveMessage = new String(bytes, 0, readByteCount, "UTF-8");
System.out.println("[클라이언트] 데이터 받음: " + receiveMessage);
*/
// 데이터 보내기2
String sendMessage = "이것이 자바다 TCP 전송";
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(sendMessage);
dos.flush();
System.out.println("[클라이언트] 데이터 보냄: " + sendMessage);
// 데이터 받기2
DataInputStream dis = new DataInputStream(socket.getInputStream());
String receiveMessage = dis.readUTF();
System.out.println("[클라이언트] 데이터 받음: " + receiveMessage);
// Socket 닫기
socket.close();
System.out.println("[클라이언트] 연결 끊음");
} catch (UnknownHostException e) {
// IP 표기 방법이 잘못 되었을 경우
} catch (IOException e) {
// 해당 포트의 서버에 연결할 수 없는 경우
}
}
}
실행 결과
EchoServer를 실행 후 EchoClient를 실행하면 클라이언트에서 보낸 메시지가 서버에 전송되고 다시 서버에서 클라이언트로 전송됨
클라이언트를 계속 실행하면 서버에는 메시지내역이 쌓임
EchoServer 실행 결과
------------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.
------------------------------------------------
[서버] 시작됨
[서버] 연결 요청을 기다림
[서버] localhost의 연결 요청을 수락함
[서버] 받은 데이터를 다시 보냄: 이것이 자바다 TCP 전송
[서버] localhost의 연결을 끊음
[서버] 연결 요청을 기다림
EchoClient 실행 결과
[클라이언트] 연결 성공
[클라이언트] 데이터 보냄: 이것이 자바다 TCP 전송
[클라이언트] 데이터 받음: 이것이 자바다 TCP 전송
[클라이언트] 연결 끊음
3. UDP 네트워킹
UDP 네트워킹
UDP는 발신자가 일방적으로 수신자에게 데이터를 보내는 방식으로 TCP처럼 연결 요청 및 수락 과정이 없기 때문에 TCP보다 데이터 전송 속도가 상대적으로 빠름
고정 회선이 아니라 여러 회선을 통해 데이터가 전송되기 때문에 특정 회선의 속도에 따라 데이터가 순서대로 전달되지 않거나 잘못된 회선으로 인해 데이터 손실이 발생할 수 있음
하지만 실시간 영상 스트리밍에서 한 컷의 영상이 손실되더라도 영상은 계속해서 수신되므로 문제가 되지 않아 데이터 전달의 신뢰성보다 속도가 중요하다면 UDP를 사용하고 데이터 전달이 신뢰성이 중요하다면 TCP를 사용해야 함
자바는 UDP 네트워킹을 위해 java.net 패키지에서 DatagramSocket과 DatagramPacket 클래스를 제공함
DatagramSocket은 발신점과 수신점에 해당하고 DatagramPacket은 주고받는 데이터에 해당함
UDP 서버
UDP 서버를 위한 DatagramSocket객체를 생성할 때는 바인딩할 Port 번호를 생성자 매개값으로 제공해야 함
DatagramSocket datagramSocket = new DatagramSocket(50001);
UDP 서버는 클라이언트가 보낸 DatagramPacket을 항상 받을 준비를 해야 하는데 이 역할을 하는 메서드가 receive() 임
receive() 메서드는 데이터를 수신할 대까지 블로킹되고 데이터가 수신되면 매개값으로 주어진 DatagramPacket에 저장함
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
datagramSocket.receive(receivePacket);
DatagramPacket 생성자의 첫 번째 매개값은 수신된 데이터를 저장할 배열이고 두 번째 매개값을 수신할 수 있는 최대 바이트 수이며 보통 첫 번째 바이트 배열의 크기를 줌
receive() 메서드가 실행된 후 수신된 데이터와 바이트 수를 얻는 방법은 다음과 같음
byte[] bytes = receivePacket.getData();
int num = receivePacket.getLength();
읽은 데이터가 문자열이라면 다음과 같이 String 생성자를 이용해서 문자열을 얻을 수 있음
String data = new String(bytes, 0, num, "UTF-8");
반대로 UDP 서버가 클라이언트에서 처리 내용을 보내려면 클라이언트 IP 주소와 Port 번호가 필요한데 이것은 receive()로 받은 DatagramPacket에서 얻을 수 있음
getSocketAddress()메서드를 호출하면 정보가 담긴 SocketAddress 객체를 얻을 수 있음
SocketAddress socketAddress = receivePacket.getSocketAddress();
이렇게 얻은 SocketAddress 객체는 다음과 같이 클라이언트로 보낼 DatagramPacket을 생성할 때 네 번째 매개값으로 사용됨
DatagramPacket 생성자의 첫 번째 매개값은 바이트 배열이고 두 번째는 시작 인덱스, 세 번째는 보낼 바이트 수임
String data = "처리 내용";
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
DatagramPacket을 클라이언트로 보낼 때는 DatagramSocket의 send() 메소드를 이용함
더 이상 UDP 클라이언트의 데이터를 수신하지 않고 UDP 서버를 종료하고 싶을 경우에는 DatagramSocket의 close() 메서드를 호출하면 됨
datagramSocket.send(sendPacket);
datagramSocket.close();
NewsServer
UDP 클라이언트가 구독하고 싶은 뉴스 10개를 전송하는 UDP 서버예제
package chapter19.sec04;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class NewsServer {
private static DatagramSocket datagramSocket;
public static void main(String[] args) {
System.out.println("------------------------------------------------");
System.out.println("서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.");
System.out.println("------------------------------------------------");
// UDP 서버 시작
startServer();
// 키보드 입력
Scanner scanner = new Scanner(System.in);
while (true) {
String key = scanner.nextLine();
if (key.toLowerCase().equals("q")) {
break;
}
}
scanner.close();
// UDP 서버 종료
stopServer();
}
private static void startServer() {
// 작업 스레드 정의
Runnable runnable = () -> {
try {
// DatagramSocket 생성 및 Port 바인딩
datagramSocket = new DatagramSocket(50001);
System.out.println("[서버] 시작됨");
while (true) {
// 클라이언트가 구독하고 싶은 뉴스 주제 얻기
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
datagramSocket.receive(receivePacket);
String newsKind = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
// 클라이언트의 IP와 Port 얻기
SocketAddress socketAddress = receivePacket.getSocketAddress();
// 10개의 뉴스를 클라이언트로 전송
for (int i = 1; i <= 10; i++) {
String data = newsKind + ": 뉴스" + i;
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
datagramSocket.send(sendPacket);
}
}
} catch (Exception e) {
System.out.println("[서버] " + e.getMessage());
}
};
new Thread(runnable).start();
}
public static void stopServer() {
datagramSocket.close();
System.out.println("[서버] 종료됨");
}
}
UDP 클라이언트
UDP 클라이언트는 서버에 요청 내용을 보내고 그 결과를 받는 역할을 함
UDP 클라이언트를 위한 DatagramSocket 객체는 기본 생성자로 생성하고 Port 번호는 자동으로 부여되기 때문에 따로 지정할 필요가 없음
DatagramSocket datagramSocket = new DatagramSocket();
요청 내용을 보내기 위한 DatagramPacket을 생성하는 방법은 다음과 같음
DatagramPacket 생성자의 첫 번째 매개값은 바이트 배열이고, 두 번째 매개값은 바이트 배열에서 보내고자 하는 바이트 수임
세 번째 매개값은 UDP 서버의 IP와 Port 정보를 가지고 있는 InetSocketAddress 객체임
String data = "요청 내용";
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.length, new InetSocketAddress("localhost", 50001));
생성된 DatagramPacket을 매개값으로 해서 DatagramSocket의 send() 메서드를 호출하면 UDP서버로 DatagramPacket이 전송됨
UDP 서버에서 처리 결과가 언제 올지 모르므로 항상 받을 준비를 하기 위해 receive() 메서드를 호출하고 receive() 메소드는 데이터를 수신할 때까지 블로킹 되고 데이터가 수신되면 매개값으로 주어진 DatagramPacket에 저장하는 부분은 UDP 서버와 동일함
더 이상 UDP 서버와 통신할 필요가 없다면 DatagramSocket을 닫기 위해 close() 메소드를 호출함
datagramSocket.send(sendPacket);
datagramSocket.close();
NewsClient
NewsServer로 구독하고 싶은 뉴스 주제를 보내고 관련 뉴스 10개를 받는 UDP 클라이언트
package chapter19.sec04;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class NewsClient {
public static void main(String[] args) {
// DatagramSocket 생성
try {
DatagramSocket datagramSocket = new DatagramSocket();
// 구독하고 싶은 뉴스 주제 보내기
String data = "정치";
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.length, new InetSocketAddress("localhost", 50001));
datagramSocket.send(sendPacket);
while (true) {
// 뉴스 받기
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
datagramSocket.receive(receivePacket);
// 문자열로 변환
String news = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
System.out.println(news);
// 10 번째 뉴스를 받으면 while 문 종료
if (news.contains("뉴스10")) {
break;
}
}
} catch (Exception e) {
}
}
}
실행 결과
NewsServer를 실행 후 NewsClient를 실행하면 Server에서 반복문으로 보낸 뉴스가 클라이언트에서 출력되는 것을 확인할 수 있음
NewsServer 실행 결과
------------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.
------------------------------------------------
[서버] 시작됨
NewsClient 실행 결과
정치: 뉴스1
정치: 뉴스2
정치: 뉴스3
정치: 뉴스4
정치: 뉴스5
정치: 뉴스6
정치: 뉴스7
정치: 뉴스8
정치: 뉴스9
정치: 뉴스10
'기타 개발 강의 및 책 정리 > 이것이자바다 개정판' 카테고리의 다른 글
Chapter 17 - 스트림 요소 처리1(Stream), 스트림이란?, 내부 반복자, 중간 처리와 최종 처리, 스트림 얻기, 요소 걸러내기(필터링), 요소 변환(매핑) (0) | 2025.03.13 |
---|---|
Chapter 16 - 람다식 (0) | 2025.03.10 |
chapter4 - 조건문과 반복문 확인문제, 추가내용 / 이것이 자바다(개정판) (0) | 2024.02.13 |
chapter3 - 연산자 확인문제, / 이것이 자바다(개정판) (0) | 2024.02.12 |
chapter1 - 자바시작하기 확인문제 (일부만), chapter2 - 변수와 타입 확인문제 / 이것이 자바다(개정판) (1) | 2024.02.07 |