[Java] UDP 네트워킹

Bam·2024년 3월 26일
0

Java

목록 보기
94/98
post-thumbnail

UDP

UDP는 연결 요청과 수락과정 없이 데이터를 일방적으로 보내는 통신 프로토콜입니다. 연결과정이 없기 때문에 TCP에 비해 속도가 빠르며, 고정회선이 아닌 여러 회선을 사용하기 때문에 데이터가 순서대로 도착하지 않아서 데이터가 일부 손실될 수 있다는 낮은 신뢰성을 특징으로 갖습니다.

따라서 속도보다 신뢰성이 중요하다면 TCP, 신뢰성보다 속도가 중요하면 UDP를 사용합니다.

자바에서는 UDP 네트워킹을 위해서 java.net 패키지에서 DatagramSocket, DatagramPacket 클래스를 제공하고 있습니다. DatagramSocket은 발신지와 수신지에서 사용하는 클래스이고, DatagramPacket은 통신되는 데이터에 사용되는 클래스입니다.


UDP 서버 프로그래밍

UDP 서버는 DatagramSocket 객체를 생성하고 이용합니다. 마찬가지로 바인딩할 포트 번호를 지정해주어야합니다.

다음 코드는 데이터를 송수신하는 기본적인 기능만 갖춘 UDP 서버 코드입니다.

public class UDPServer {
    private static DatagramSocket datagramSocket = null;

    public static void main(String[] args) {
        System.out.println("* 서버 종료는 q 입력 *");

		//UDP 서버 시작
        startServer();

        Scanner scanner = new Scanner(System.in);

        while (true) {
            String key = scanner.nextLine();

            if (key.equals("q")) {
                break;
            }
        }
        scanner.close();
        //UDP 서버 종료
        stopServer();
    }

    public static void startServer() {	//서버 시작 메소드
    	//서버 작업 스레드
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                	//DatagramSocket 객체 생성, Port binding
                    datagramSocket = new DatagramSocket(50001);
                    System.out.println(datagramSocket.getLocalPort() + "번 포트에서 서버 실행");

                    while (true) {
                    	//클라이언트로 부터 데이터 받기
                        DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
                        datagramSocket.receive(receivePacket);

                        String fromClientData =
                                new String(
                                        receivePacket.getData(), 0,
                                        receivePacket.getLength(), "UTF-8"
                                );
                                
                        //클라이언트의 IP, Port number 취득
                        SocketAddress socketAddress = receivePacket.getSocketAddress();
                        
                        //클라이언트로부터 받은 데이터를 가공해서 다시 클라이언트로 전송
                        String data = "서버가 보내는 데이터: " + fromClientData;
                        byte[] bytes = data.getBytes("UTF-8");
                        DatagramPacket sendPacket =
                                new DatagramPacket(bytes, 0, bytes.length, socketAddress);

                        datagramSocket.send(sendPacket);
                    }
                }
                catch (IOException e) {
                    System.err.println(e);
                }
            }
        };

        thread.start();
    }

    public static void stopServer() {	//서버 종료 메소드
    	//서버 종료, Port unbinding
        datagramSocket.close();
        System.out.println("서버 종료");
    }
}

여기서 유심히 볼 부분은 다음과 같은 부분들 입니다.

//클라이언트로 부터 데이터 받기
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);

DatagramPacket 생성자의 첫 번째 매개변수는 수신한 데이터를 저장할 배열, 두 번째 매개변수는 수신 가능한 최대 바이트 수를 의미합니다.

datagramSocket.receive(receivePacket);

UDP 통신은 연결이 없기 때문에 서버가 열리면 클라이언트의 DatagramPacket을 언제나 받을 수 있도록 대기해야합니다. 이런 역할을 receive() 메소드가 수행하는데, receive()는 데이터를 수신할 때 까지 블로킹되어있다가 데이터가 수신되면 매개변수로 전달된 DatagramPacket 객체에 저장합니다

//클라이언트의 IP, Port number 취득
SocketAddress socketAddress = receivePacket.getSocketAddress();

데이터를 다시 클라이언트에게 전송하기 위해서 클라이언트의 IP와 Port 번호가 필요한데요. 이는 receive()를 통해 받은 DatagramPacket 객체 내부에 정보가 들어있습니다. 이를 통해 정보가 담긴 SocketAddress를 전송에 활용합니다.


UDP 클라이언트 프로그래밍

이번엔 데이터를 송수신하는 기본적인 기능만 갖춘 클라이언트를 만들어보겠습니다. 서버와 동일하게 DatagramSocket 클래스를 이용합니다.

public class UDPClient {
    public static void main(String[] args) {
        try {
        	//DatagramSocket 객체 생성
            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);
            
            //서버로부터 데이터 수신
            DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
            datagramSocket.receive(receivePacket);
            String str =
                    new String(
                            receivePacket.getData(), 0,
                            receivePacket.getLength(), "UTF-8"
                    );
            System.out.println(str);

            datagramSocket.close();
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

datagramSocket.send(sendPacket);

send() 메소드를 이용하면 UDP 서버로 DatagramPacket을 전송합니다.

datagramSocket.receive(receivePacket);

마찬가지로 클라이언트 또한 언제든지 서버의 처리 결과를 받기 위해서 receive() 메소드를 사용합니다.

0개의 댓글