자바칩

[자바의 신] 28장. Socket과 Datagram: 문제 풀이 본문

Study/Java

[자바의 신] 28장. Socket과 Datagram: 문제 풀이

아기제이 2024. 5. 29. 09:44
728x90

정리해 봅시다

 

1. TCP 통신과 UDP 통신의 차이는 무엇인가요?

통신 방법 차이점
TCP - 상대 서버가 데이터를 받았는지를 확실히 보장 가능
- 내부적으로 처리되는 절차가 매우 복잡하여 UDP보다 비싸고, 느리고, 무거움
UDP - 상대 서버가 데이터를 받았는지 보장 불가능
- 내부적으로 처리되는 절차가 덜 복잡하여 TCP보다 싸고, 빠르고, 가벼움

 

 

2. 네트워크 통신 시 포트 번호를 지정하는 이유는 무엇인가요?

포트 번호를 지정한 곳에서만 통신할 수 있게 하기 위해서이다.
일반적인 웹 애플리케이션에서는 80이라는 번호의 포트를 사용한다. 이것은 정해져 있는 것이다. 만약 99를 쓰고 싶다면, 웹 서버에 99번을 사용한다고 지정을 해 놓고, 사용자가 웹 서버에 붙기 위해서 주소 뒤에 콜론(:)을 붙인 뒤 99라고 적어주어야 한다(즉 URL을 브라우저에서 입력하면 자동으로 :80이 붙은 것과 같다). 또 다른 예로 웹으로 SSL이라는 안전한 통신을 하려면 443이라는 포트를 사용하게 된다. 이렇게 정해져 있는 포트는 되도록이면 다른 용도로 사용하지 않는 것이 좋다. 따라서, 0~1023까지는 사용하는 것이 제한되어 있다. 하지만 포트는 16비트로 구성되어 65,535까지 사용할 수 있으니 그 외의 값들은 임의로 사용하면 된다.

 

 

3. ServerSocket 클래스의 용도는 무엇인가요?

서버에서 데이터를 받을 때 ServerSocket 클래스를 사용한다.
데이터를 받는 쪽(보통 서버)에서 데이터를 보내는 쪽(보통 클라이언트)의 요청을 받으면, 요청에 대한 Socket 객체를 만들어서 데이터를 처리한다. Socket 객체는 별도로 new 키워드를 사용하여 만들 필요는 없고 ServerSocket 클래스에서 제공하는 accept() 메소드에서 클라이언트 요청이 생기면 Socket 객체를 생성해서 전달해준다.
생성자 설명
ServerSocket() - 서버 소켓 객체만 생성한다.
- 별도로 연결 작업을 해야만 대기가 가능하다.
ServerSocket(int port) - 지정된 포트를 사용하는 서버 소켓을 생성한다.
- 객체를 생성하자마자 연결을 대기할 수 있는 상태가 된다.
ServerSocket(int port, int backlog) - 지정된 포트와 backlog 개수를 가지는 소켓을 생성한다.
- 객체를 생성하자마자 연결을 대기할 수 있는 상태가 된다.
ServerSocket(int port, int backlog,
InetAddress bindAddr)
- 지정된 포트와 backlog 개수를 가지는 소켓을 생성하며, bindAddr에 있는 주소에서의 접근만을 허용한다.
- 객체를 생성하자마자 연결을 대기할 수 있는 상태가 된다.
*backlog란?
ServerSocket 객체가 바빠서 연결 요청을 처리 못하고 대기시킬 때가 있는데, 그 때의 최대 대기 개수라고 보면 된다. backlog의 개수를 지정하지 않을 경우, backlog의 개수는 50개가 된다. 그런데, 만약 직접 만든 애플리케이션의 접속이 원활하지 않는다면 이 개수를 적절하게 증가시키는 것이 좋다(절대적으로 좋은 개수는 없다).

 

 

4. ServerSocket 클래스의 accpet() 메소드의 용도는 무엇인가요?

새로운 소켓 연결을 기다리고, 연결이 되면 Socket 객체를 리턴한다.

 

 

5. Socket 클래스의 용도는 무엇인가요?

TCP 통신을 자바에서 수행하려면 Socket 클래스를 사용하면 된다. Socket 클래스는 데이터를 받는 쪽(보통 서버)에서 클라이언트 요청을 받으면, 요청에 대한 Socket 객체를 생성하여 데이터를 처리한다. 즉, 이 Socket 클래스는 서버 쪽이 되었든 클라이언트 쪽이 되었든 원격에 있는 장비와의 연결 상태를 보관하고 있다고 생각하면 된다.
데이터를 받는 서버에서는 클라이언트에서 접속을 하면 Socket 객체를 생성하지만, 데이터를 보내는 클라이언트에서는 Socket 객체를 직접 생성해야만 한다.
생성자 설명
Socket() 소켓 객체만 생성
Socket(Proxy proxy) 프록시 관련 설정과 함께 소켓 객체만 생성
Socket(SocketImpl impl) 사용자가 지정한 SocketImpl 객체를 사용하여 소켓 객체만 생성
Socket(InetAddreses address, int port) 소켓 객체 생성 후 address와 port를 사용하는 서버에 연결
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 소켓 객체 생성 후 address와 port를 사용하는 서버에 연결하며, 지정한 localAddr와 localPort에 접속
Socket(String host, int port) 소켓 객체 생성 후 host와 port를 사용하는 서버에 연결
Socket(String host, int port, InetAddress localAddr, int localPort) 소켓 객체 생성 후 host와 post를 사용하는 서버에 연결하며, 지정된 localAddr와 localPort에 접속

 

 

6. DatagramSocket 클래스의 용도는 무엇인가요?

UDP 통신에서 데이터를 주고 받기 위한 클래스이다. TCP와는 다르게 클래스 하나에서 보내는 역할받는 역할을 모두 수행할 수 있다.
리턴 타입 메소드 설명
void receive(DatagramPacket packet) 메소드 호출 시 요청을 대기하고, 만약 데이터를 받았을 때에는
packet 객체에 데이터를 저장
void send(DatagramPacket packet) packet 객체에 있는 데이터 전송

 

7. DatagramPacket 클래스의 용도는 무엇인가요?

TCP 통신에서는 스트림 객체를 얻어서 데이터를 주거나 받았지만, UDP 통신에서는 스트림을 사용하지 않고 DatagramPacket이라는 클래스를 사용하여 데이터를 주거나 받는다.
DatagramPacket의 생성자 중 단 하나, 매개변수가 byte[] 배열과 정수값(byte[] 배열의 길이)만 있는 경우만 데이터를 받기 위한 생성자이며, 나머지 생성자들은 데이터를 전송하기 위한 생성자들이다.
리턴 타입 메소드 설명
byte[] getData() byte[]로 전송받은 데이터 리턴
int getLength() byte[]로 전송받은 데이터의 길이 리턴

 


직접해 봅시다

SocketServerSample.java

 
    package e.network;

    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;

    public class SocketServerSample {
        public static void main(String[] args) {
            SocketServerSample sample = new SocketServerSample();
            sample.startReplyServer();  // 7번
        }
 
        // 1번
        public void startReplyServer() {    
            ServerSocket server = null;
            Socket client = null;
            try {
                server = new ServerSocket(9999);
                while (true) {
                    System.out.println("Server: Waiting for request.");
                    client = server.accept();
                    System.out.println("Server: Accepted.");
                    OutputStream stream = client.getOutputStream();     // 2번
                    // 3번
                    BufferedOutputStream out = new BufferedOutputStream(stream);
                    byte[] bytes = "OK".getBytes();
                    out.write(bytes);
                    out.close();
                    stream.close();
                    client.close();
                    System.out.println("----------");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (server != null) {
                    try {
                        server.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

 

SocketClientSample.java

 
    package e.network;

    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;

    public class SocketClientSample {
        public static void main(String[] args) {
            SocketClientSample sample = new SocketClientSample();
            sample.sendSocketSample();
        }

        public void sendSocketSample() {
            for (int loop = 0; loop < 3; loop++) {
                sendAndReceiveSocketData();  // 8번
            }
        }

        // 4번
        public void sendAndReceiveSocketData() {
            Socket socket = null;
            try {
                System.out.println("Client: Connecting");
                socket = new Socket("127.0.0.1", 9999);
                System.out.println("Client: Connect status = " + socket.isConnected());
                Thread.sleep(1000);
                InputStream stream = socket.getInputStream();   // 5번
                // 6번
                BufferedInputStream in = new BufferedInputStream(stream);
                byte[] readByte = new byte[256];
                in.read(readByte);
                System.out.println("Client: Received data = " + new String(readByte).trim());
                in.close();
                stream.close();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }