ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • UDP 네트워킹
    JAVA 2023. 3. 20. 15:34
    • UDP(User Datagram Protocol) : 발신자가 일방적으로 수신자에게 데이터를 보내는 방식
    • 장점
      TCP와 달리 연결 요청 및 연결 수략 과정이 없기 때문에 상대적으로 데이터 전송 속도가 빠르다.
    • 단점
      데이터 전송 회선이 고정되지 않기 때문에 데이터 손실되거나 데이터의 순서가 섞일 수 있다.
    • 데이터 전달의 신뢰성보다 속도가 중요한 통신에서 사용
      - 실시간 영상 송출 등
    • 자바에서 DatagramSocket과 DatagramPacket 클래스(java.net)를 통해 UDP 네트워킹을 지원한다.
      • DatagramSocket
        - 발신점과 수신점을 담당
      • DatagramPacket
        - 데이터 송수신에 관여

     


    UDP 서버

    • 서버는 항상 클라이언트가 보낼 DatagramPacket을 받을 준비를 해야 한다.

     

    //송수신 포트를 지정하여 DatagrameSocket 객체 생성
    DatagramSocket datagrameSocket = new DatagramSocket(50001);

     

     

    • recevie() 메소드를 이용해 데이터를 받는다.
      - 데이터를 받을 수 있는 비어있는 DatagramPacket 객체를 미리 준비해두었다가 데이터가 들어올 때 받아내는 방식이다.
      - 데이터를 수신할 때까지 블로킹된다.

     

    //클라이언트가 보낸 데이터를 받아낼 DatagramPacket 준비
    DatagramPacket datagramPacket = new DatagramPacket(new byte[1024], 1024);    //수신한 바이트 데이터를 저장할 배열과 최대 수신할 수 있는 바이트 수를 매개값으로 설정
    datagramPacket.receive(receivePacket);    //receive() 메소드로 데이터를 수신

     

     

    • receive 메소드를 실행하여 받은 데이터 정보를 얻는 방법

     

    //receive 메소드가 실행된 이후 수쇤된 바이트 데이터 확인
    byte[] bytes = receivePacket.getData();    //수신한 바이트 데이터를 저장
    int num = receivePacket.getLength();    //실제로 읽은 바이트 수를 리턴
     
    //받은 바이트 데이터를 문자열로 변환
    Stirng data = new String(bytes, 0, num, "UTF-8");    //실제로 읽은 바이트 수만큼만 문자열로 변환해야 함

     

     

    • TCP 통신에서는 서버의 IP 주소와 포트 번호만 알아도 데이터 송수신이 가능했지만 UDP 통신에서는 서버와 연결 요청/수락 과정이 없기 때문에 서버에서 클라이언트로 메시지를 보내기 위해서는 클라이언트의 IP 주소와 포트 번호도 알아야 한다.
      - DatagramPacket에는 데이터를 송신한 쪽(클라이언트)의 IP 정보와 포트 정보가 들어있으며, 이를 이용해 데이터를 보낸 쪽에 응답 데이터를 보낼 수 있다.

     

    //데이터를 보낸 쪽의 IP와 포트 정보를 추출
    SocketAddress socketAddress = receivePacket.getSocketAddress();
     
    //클라이언트로부터 받은 데이터에 대한 처리 내용을 보내기 위해 준비하는 과정
    String data = "처리 내용";
    byte[] bytes = data.getBytes("UTF-8");
    DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
     
    //전송할 바이트 배열의 길이만 입력해도 0 인덱스부터 데이터를 읽어서 DatagramPacket 갱체 생성 가능
    DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.length, socketAddress);
     
    //DatagramPacket에 담은 데이터를 DatagramSocket 객체를 통해 전송
    datagramSocket.send(sendPacket);

     

     

    • UDP 서버 종료

     

    //UDP 서버 종료
    datagramSocket.close();

     

     


    UDP 클라이언트

    • 서버에 요청 내용을 보내고 서버에서 처리한 결과를 받는 역할
    • Port 번호는 내부적으로 자동 부여되기 때문에 DatagramSocket 객체를 기본 생성자로 생성

     

    //기본 생성자로 DatagramSocket 객체 생성
    DatagramSocket datagramSocket = new DatagramSocket();

     

     

    • 생성한  DatagramPacket 객체에 요청 내용을 저장하여 서버에 전송

     

    //요청 내용을 담을 DatagramPacket 객체 생성
    String data = "요청 내용";
    byte[] bytes = dat.getBytes("UTF-8");
    DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.lengthnew InetSocketAddress("localhost"50001));
     
     
    //DatagramSocket을 통해 요청 내용을 서버에 전송
    datagramSocket.send(sendPacket);

     

     

    • 더 이상 서버에서 보내는 데이터를 그만 받으려면 DatagramSocket을 종료하면 된다.

     

    //UDP 통신 종료. 
    datagramSocket.close();

     


    UDP 통신 프로그램 예제

    • 클라이언트로부터 구독할 주제를 받으면 10개의 뉴스를 제공하는 프로그램

     

    서버 프로그램

     

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    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();
     
        }
     
        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);    //읽을 수 있는 최대 바이트 수는 저장할 수 있는 바이트 수를 초과할 수 없다.
                            System.out.println("클라이언트의 희망 뉴스 종류 얻기위해 대기");
                            datagramSocket.receive(receivePacket);
                            String newsKind = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
                            
                            //클라이언트의 IP와 Port 정보가 있는 SocketAddress 얻기
                            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);
                                
                                Thread.sleep(1000);    //뉴스 전송 간격 추가
                            }
                        }
                        
                    } catch (Exception e) {
                        System.out.println("[서버] " + e.getMessage());
                    }
                }
            };
            
            //작업 스레드 시작
            thread.start();
        }
     
        public static void stopServer() {
            //DatagramSocket을 단고 Port 언바인딩
            datagramSocket.close();
            System.out.println("[서버] 종료됨");
        }
     
    }

     

    클라이언트 프로그램

     

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    public class NewsClient {
     
        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, 0, bytes.lengthnew 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;
                    }
                }
                
                //DatagramSocket 닫기
                datagramSocket.close();
                
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            
        }
     
    }

     

     

    실행 결과

     

    서버 프로그램 콘솔 내용

     

    클라이언트 프로그램 콘솔 내용

     


    'JAVA' 카테고리의 다른 글

    JSON 데이터 형식  (0) 2023.03.20
    TCP 네트워킹  (0) 2023.03.20
    네트워크 입출력  (0) 2023.03.20
    보조 스트림  (0) 2023.03.17
    데이터 입출력  (0) 2023.03.17
Designed by Tistory.