관리 메뉴

개발공부기록

Chapter19 - 네트워크 입출력, IP 주소 얻기, TCP 네트워킹, UDP 네트워킹 본문

기타 개발 강의 및 책 정리/이것이자바다 개정판

Chapter19 - 네트워크 입출력, IP 주소 얻기, TCP 네트워킹, UDP 네트워킹

소소한나구리 2025. 2. 11. 23:36
728x90

1. 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

 

728x90