Chapter 19 - 네트워크 입출력

김태원·2023년 1월 31일
0

네트워크 기초

네트워크(Network)는 여러 컴퓨터들을 통신 회선으로 연결한 것을 말한다.

LAN(Local Area Network)은 가정, 회사 건물, 특정 영역에 존재하는 컴퓨터를 연결한 것이고, WAN(Wide Area Network)은 LAN을 연결한 것이다.
WAN이 우리가 흔히 말하는 인터넷(Internet)이다.

서버와 클라이언트

네트워크에서 유무선으로 컴퓨터가 연결되어 있다면 실제로 데이터를 주고받는 행위는 프로그램들이 한다.
서비스를 제공하는 프로그램을 일반적으로 서버(Server)라고 부르고, 서비스를 요청하는 프로그램을 클라이언트(Client)라고 부른다.

인터넷에서 두 프로그램이 통신하기 위해서는 먼저 클라이언트가 서비스를 요청하고, 서버는 처리 결과를 응답으로 제공해준다.

IP 주소

IP(Internet Protocol) 주소는 네트워크 어댑터(LAN 카드)마다 할당된다.
만약 컴퓨터에 두 개의 네트워크 어댑터가 장착되어 있다면, 두 개의 IP 주소를 할당받을 수 있다.

Port 주소

컴퓨터 내부에서 실행하는 서버를 선택하기 위해서는 Port 주소가 필요하다.
Port는 운영체제가 관리하는 서버 프로그램의 연결 번호이다.

클라이언트도 서버에서 보낸 정보를 받기 위해서는 Port 번호가 필요한데, 서버와 같이 고정적인 Port 번호에 바인딩하는 것이 아니라 운영체제가 자동으로 부여하는 번호를 사용한다.
이 번호는 클라이언트가 서버로 요청할 때 함께 전송되어 서버가 클라이언트로 데이터를 보낼 때 사용된다.

프로그램에서 사용할 수 있는 전체 Port 번호의 범위는 0~65535로, 다음과 같이 사용 목적에 따라 세 가지 범위를 가진다.

IP 주소 얻기

자바는 IP 주소를 java.net 패키지의 InetAddress로 표현한다. 이를 이용하면 로컬 컴퓨터의 IP 주소를 얻읋 수 있고, 도메인 이름으로 DNS(Domain Name System)에서 검색한 후 IP 주소를 가져올 수도 있다.

로컬 컴퓨터의 InetAddress를 얻고 싶다면 InetAddress.getLocalHost() 메소드를 다음과 같이 호출하면 된다.

InetAddress ia = InetAddress.getLocalHost();

만약 컴퓨터의 도메인 이름을 알고 있다면 다음 두 개의 메소드를 사용하여 InetAddress 객체를 얻을 수 있다.

InetAddress ia = InetAddress.getByName(String domainName);
InetAddress[] iaArr = InetAddress.getAllByName(String domainName);

이 메소드들로부터 얻은 InetAddress 객체에서 IP 주소를 얻으려면 getHostAddress() 메소드를 다음과 같이 호출하면 된다.

리턴값은 문자열로 된 IP 주소이다.

String ip = InetAddress.getHostAddress();

TCP 네트워킹

IP 주소로 프로그램들이 통신할 때는 약속된 데이터 전송 규약이 있다. 이것을 전송용 프로토콜(Protocol)이라고 부른다. 인터넷에서 전송용 프로토콜은 TCP(Transmission Control Protocol)UDP(User Datagram Protocol)가 있다.

자바는 TCP 네트워킹을 위해 java.net 패키지에서 ServerSocket과 Socket 클래스를 제공하고 있다.
ServerSocket은 클라이언트의 연결을 수락하는 서버 쪽 클래스이고, Socket은 클라이언트에서 연결 요청할 때와 클라이언트와 서버 양쪽에서 데이터를 주고 받을 때 사용되는 클래스이다.

TCP 서버

TCP 서버 프로그램을 개발하려면 우선 ServerSocket 객체를 생성해야 한다.
다음은 50001번 port에 바인딩하는 ServerSocket을 생성하는 코드이다.

ServerSocket serverSocket = new ServerSocket(50001);

예제를 보자

package ch19.sec03.exam01;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

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.equalsIgnoreCase("q")) {
                break;
            }
        }
        scanner.close();

        // TCP 서버 종료
        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() + "의 연결 요청을 수락함");

                        // 연결 끊기
                        socket.close();
                        System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음");
                    }
                } catch (IOException e) {
                    System.out.println("[서버] " + e.getMessage());
                }
            }
        };
        // 스레드 시작
        thread.start();
    }

    public static void stopServer() {
        try {
            // ServerSocket을 닫고 Port 언바인딩
            serverSocket.close();
            System.out.println("[서버] 종료됨 ");
        } catch (IOException e1) {
        }
    }
}

TCP 클라이언트

클라이언트가 서버에 연결 요청을 하려면 Socket 객체를 생성할 때 생성자 매개값으로 서버 IP 주소와 Port 번호를 제공하면 된다.
로컬 컴퓨터에서 실행하는 서버로 연결 요청을 할 경우에는 IP 주소 대신 localhost를 사용할 수 있다.

예제를 보자.

package ch19.sec03.exam01;

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

public class ClientExample {
    public static void main(String[] args) {
        try {
            // Socket 생성과 동시에 localhost의 50001 Port로 연결 요청;
            Socket socket = new Socket("localhost", 50001);

            System.out.println("[클라이언트] 연결 성공");

            // Socket 닫기
            socket.close();
            System.out.println("[클라이언트] 연결 끊음");
        } catch (UnknownHostException e) {
            // IP 표기 방법이 잘못되었을 경우
        } catch (IOException e) {
            // 해당 포트의 서버에 연결할 수 없는 경우
        }
    }
}
-----------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.
-----------------------------------------------
[서버] 시작됨

[서버] 연결 요청을 기다림

[서버] localhost의 연결 요청을 수락함
[서버] localhost의 연결을 끊음

[서버] 연결 요청을 기다림

q
[서버] 종료됨 
[서버] Socket closed

이전 예제인 ServerExample을 먼저 실행시키고 ClientExmaple을 실행하면 다음과 같은 내용이 Console 뷰에 출력된다.

입출력 스트림으로 데이터 주고 받기

클라이언트가 연결 요쳥(connect())을 하고 서버가 연결 수락(accept())했다면, 다음 그림과 같이 양쪽의 Socket 객체로부터 각각 입력 스트림(InputStream)과 출력 스트림(OutputStream)을 얻을 수 있다.

다음은 TCP 클라이언트가 보낸 메시지를 다시 돌려보내는 Echo(메아리) TCP 서버를 구현한 예제이다.

package ch19.sec03.exam02;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class EchoServer {
    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.equalsIgnoreCase("q")) {
                break;
            }
        }
        scanner.close();

        // TCP 서버 종료
        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() + "의 연결 요청을 수락함");

                        // 데이터 받기
                        DataInputStream dis = new DataInputStream(socket.getInputStream());
                        String message = dis.readUTF();

                        // 데이터 보내기
                        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();
    }

    public static void stopServer() {
        try {
            // ServerSocket을 닫고 Port 언바인딩
            serverSocket.close();
            System.out.println("[서버] 종료됨 ");
        } catch (IOException ignored) {
        }
    }
}
package ch19.sec03.exam02;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;

public class EchoClient {
    public static void main(String[] args) {
        try {
            // Socket 생성과 동시에 localhost의 50001 포트로 연결 요청;
            Socket socket = new Socket("localhost", 50001);

            System.out.println("[클라이언트] 연결 성공");

            // 데이터 보내기
            String sendMessage = "나는 자바가 좋아~~";
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
            dos.writeUTF(sendMessage);
            dos.flush();
            System.out.println("[클라이언트] 데이터 보냄: " + sendMessage);

            // 데이터 받기
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            String receiveMessage = dis.readUTF();
            System.out.println("[클라이언트] 데이터 받음: " + receiveMessage);
            // ---------------------------------------------------------------------------

            // 연결 끊기
            socket.close();
            System.out.println("[클라이언트] 연결 끊음");
        } catch (Exception ignored) {
        }
    }
}
-----------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.
-----------------------------------------------
[서버] 시작됨

[서버] 연결 요청을 기다림

[서버] localhost의 연결 요청을 수락함
[서버] 받은 데이터를 다시 보냄: 나는 자바가 좋아~~
[서버] localhost의 연결을 끊음

[서버] 연결 요청을 기다림

q
[서버] 종료됨 
[서버] Socket closed
[클라이언트] 연결 성공
[클라이언트] 데이터 보냄: 나는 자바가 좋아~~
[클라이언트] 데이터 받음: 나는 자바가 좋아~~
[클라이언트] 연결 끊음

UDP 네트워킹

UDP(User Datagram Protocol)는 발신자가 일방적으로 수신자에게 데이터를 보내는 방식으로, TCP(Transmission Control Protocol) 처럼 연결 요청 및 수락 과정이 없기 때문에 TCP보다 데이터 전송 속도가 상대적으로 빠르다.

자바는 UDP 네트워킹을 위해 java.net 패키지에서 DatagramSocket과 DatagramPacket 클래스를 제공하고 있다.
DatagramSocket은 발신점과 수신점에 해당하고 DatagramPacket은 주고 받는 데이터에 해당한다.

UDP 서버

다음 예제는 UDP 클라이언트가 구독하고 싶은 뉴스 10개를 전송하는 UDP 서버이다.

package ch19.sec04;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class NewsServer {
    private static DatagramSocket datagramSocket = null;

    public static void main(String[] args) throws Exception {
        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.equalsIgnoreCase("q")) {
                break;
            }
        }
        scanner.close();

        // UDP 서버 종료
        stopServer();
    }

    public static void startServer() {
        // 작업 스레드 정의
        Thread thread = new Thread() {
            @Override
            public void run() {
                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(), StandardCharsets.UTF_8);

                        // 클라이언트의 IP와 Port 얻기
                        SocketAddress socketAddress = receivePacket.getSocketAddress();

                        // 10개의 뉴스를 클라이언트로 전송
                        for (int i = 1; i <= 10; i++) {
                            String data = newsKind + ": 뉴스" + i;
                            byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
                            DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
                            datagramSocket.send(sendPacket);
                        }
                    }
                } catch (Exception e) {
                    System.out.println("[서버] " + e.getMessage());
                }
            }
        };
        // 스레드 시작
        thread.start();
    }

    public static void stopServer() {
        // DatagramSocket을 닫고 Port 언바인딩
        datagramSocket.close();
        System.out.println("[서버] 종료됨 ");
    }
}
-----------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력하세요.
-----------------------------------------------
[서버] 시작됨
q
[서버] 종료됨 
[서버] Socket closed

UDP 클라이언트

UDP 클라이언트를 위한 DatagramSocket 객체는 기본 생성자로 생성한다.
Port 번호는 자동으로 부여되기 때문에 따로 지정할 필요가 없다.

다음은 이전 예제인 NewsServer로 구독하고 싶은 뉴스 주제를 보내고 관련 뉴스 10개를 받는 UDP 클라이언트이다.

package ch19.sec04;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

public class NewsClient {
    public static void main(String[] args) {
        try {
            // DatagramSocket 생성
            DatagramSocket datagramSocket = new DatagramSocket();

            // 구독하고 싶은 뉴스 주제 보내기
            String data = "정치";
            byte[] bytes = data.getBytes(StandardCharsets.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(), StandardCharsets.UTF_8);
                System.out.println(news);

                // 10번째 뉴스를 받았을 경우 while 문 종료
                if (news.contains("뉴스10")) {
                    break;
                }
            }

            // DatagramSocket 닫기
            datagramSocket.close();
        } catch (Exception ignored) {
        }
    }
}
정치: 뉴스1
정치: 뉴스2
정치: 뉴스3
정치: 뉴스4
정치: 뉴스5
정치: 뉴스6
정치: 뉴스7
정치: 뉴스8
정치: 뉴스9
정치: 뉴스10

서버의 동시 요청 처리

일반적으로 서버는 다수의 클라이언트와 통신을 한다. 서버는 클라이언트들로부터 동시에 요청을 받아서 처리하고, 처 결과를 개별 클라이언트로 보내줘야 한다.

다수의 클라이언트와의 통신을 위해서는 accept()와 receive()를 제외한 요청 처리 코드를 별도의 스레드에서 작업하는 것이 좋다.

스레드를 처리할 때 주의할 점은 클라이언트의 폭증으로 인한 서버의 과도한 스레드 생성을 방지해야 한다는 것이다.

그래서 스레드풀을 사용하는 것이 바람직하다.
다음은 스레드풀을 이용해서 요청을 처리하는 방식이다.

스레드풀은 작업 처리 스레드 수를 제한해서 사용하기 때문에 갑작스런 클라이언트 폭증이 발생해도 크게 문제가 되지 않는다.
다만 작업 큐의 대기 작업이 증가되어 클라이언트에서 응답을 늦게 받을 수 있다.

TCP EchoServer 동시 요청 처리

다음은 스레드풀을 이용해서 클라리언트의 요청을 동시에 처리하는 EchoServer 예제이다.

package ch19.sec05.exam01;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class EchoServer {
    private static ServerSocket serverSocket = null;
    private static final ExecutorService executorService = Executors.newFixedThreadPool(10);

    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.equalsIgnoreCase("q")) {
                break;
            }
        }
        scanner.close();

        // TCP 서버 종료
        stopServer();
    }

    public static void startServer() {
        // 작업 스레드 정의
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                    // ServerSocket 생성 및 Port 바인딩
                    serverSocket = new ServerSocket(50001);
                    System.out.println("[서버] 시작됨\n");

                    // 연결 수락 및 데이터 통신
                    while (true) {
                        // 연결 수락
                        Socket socket = serverSocket.accept();

                        executorService.execute(() -> {
                            try {
                                // 연결된 클라이언트 정보 얻기
                                InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
                                System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");

                                // 데이터 받기
                                DataInputStream dis = new DataInputStream(socket.getInputStream());
                                String message = dis.readUTF();

                                // 데이터 보내기
                                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                                dos.writeUTF(message);
                                dos.flush();
                                System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);

                                // 연결 끊기
                                socket.close();
                                System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음\n");
                            } catch (IOException ignored) {
                            }
                        });
                    }
                } catch (IOException e) {
                    System.out.println("[서버] " + e.getMessage());
                }
            }
        };
        // 스레드 시작
        thread.start();
    }

    public static void stopServer() {
        try {
            // ServerSocket을 닫고 Port 언바인딩
            serverSocket.close();
            executorService.shutdownNow();
            System.out.println("[서버] 종료됨 ");
        } catch (IOException ignored) {
        }
    }
}

UDP EchoServer 동시 요청 처리

다음은 스레드풀을 이용해서 클라리언트의 요청을 동시에 처리하는 NewsServer 예제이다.

package ch19.sec05.exam02;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NewsServer {
    private static DatagramSocket datagramSocket = null;
    private static final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws Exception {
        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.equalsIgnoreCase("q")) {
                break;
            }
        }
        scanner.close();

        // UDP 서버 종료
        stopServer();
    }

    public static void startServer() {
        // 작업 스레드 정의
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                    // DatagramSocket 생성 및 Port 바인딩
                    datagramSocket = new DatagramSocket(50001);
                    System.out.println("[서버] 시작됨");

                    while (true) {
                        // 클라이언트가 구독하고 싶은 뉴스 종류 얻기
                        DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
                        datagramSocket.receive(receivePacket);

                        executorService.execute(() -> {
                            try {
                                String newsKind = new String(receivePacket.getData(), 0, receivePacket.getLength(), StandardCharsets.UTF_8);

                                // 클라이언트의 IP와 Port 얻기
                                SocketAddress socketAddress = receivePacket.getSocketAddress();

                                // 10개의 뉴스를 클라이언트로 전송
                                for (int i = 1; i <= 10; i++) {
                                    String data = newsKind + ": 뉴스" + i;
                                    byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
                                    DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
                                    datagramSocket.send(sendPacket);
                                }
                            } catch (Exception ignored) {
                            }
                        });
                    }
                } catch (Exception e) {
                    System.out.println("[서버] " + e.getMessage());
                }
            }
        };
        // 스레드 시작
        thread.start();
    }

    public static void stopServer() {
        // DatagramSocket을 닫고 Port 언바인딩
        datagramSocket.close();
        executorService.shutdownNow();
        System.out.println("[서버] 종료됨 ");
    }
}

JSON 데이터 형식

네트워크로 전달하는 데이터가 복잡할수록 구조화된 형식이 필요하다. 네트워크 통신에서 가장 많이 사용되는 데이터 형식은 JSON(Javascript Object Notation)이다.

JSON의 표기법은 다음과 같다.

다음은 JSON 표기법과 관련된 클래스들이다.

클래스용도
JSONObjectJSON 객체 표기를 생성하거나 파싱할 때 사용
JSONArrayJSON 배열 표기를 생성하거나 파싱할 때 사용

다음은 회원 정보를 JSON으로 만드는 예제이다.

package ch19.sec06;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;

public class CreateJsonExample {
    public static void main(String[] args) throws IOException {
        // JSON 객체 생성
        JSONObject root = new JSONObject();

        // 속성 추가
        root.put("id", "winter");
        root.put("name", "한겨울");
        root.put("age", 25);
        root.put("student", true);

        // 객체 속성 추가
        JSONObject tel = new JSONObject();
        tel.put("home", "02-123-1234");
        tel.put("mobile", "010-123-1234");
        root.put("tel", tel);

        // 배열 속성 추가
        JSONArray skill = new JSONArray();
        skill.put("java");
        skill.put("c");
        skill.put("c++");
        root.put("skill", skill);

        // JSON 얻기
        String json = root.toString();

        // 콘솔에 출력
        System.out.println(json);

        // 파일로 저장
        Writer writer = new FileWriter("member.json", StandardCharsets.UTF_8);
        writer.write(json);
        writer.flush();
        writer.close();
    }
}
package ch19.sec06;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class ParseJsonExample {
    public static void main(String[] args) throws IOException {
        // 파일로부터 JSON 읽기
        BufferedReader br = new BufferedReader(new FileReader("member.json", StandardCharsets.UTF_8));
        String json = br.readLine();
        br.close();

        // JSON 파싱
        JSONObject root = new JSONObject(json);

        // 속성 정보 읽기
        System.out.println("id: " + root.getString("id"));
        System.out.println("name: " + root.getString("id"));
        System.out.println("age: " + root.getInt("age"));
        System.out.println("student: " + root.getBoolean("student"));

        // 객체 속성 정보 읽기
        JSONObject tel = root.getJSONObject("tel");
        System.out.println("home: " + tel.getString("home"));
        System.out.println("mobile: " + tel.getString("mobile"));

        // 배열 속성 정보 읽기
        JSONArray skill = root.getJSONArray("skill");
        System.out.print("skill: ");
        for (int i = 0; i < skill.length(); i++) {
            System.out.print(skill.get(i) + ", ");
        }
    }
}
id: winter
name: winter
age: 25
student: true
home: 02-123-1234
mobile: 010-123-1234
skill: java, c, c++, 
profile
개발이 재밌어서 하는 Junior Backend Developer

0개의 댓글