CAFE

** 용어사전 **

[[용어사전]]데이터그램(Datagram)

작성자96 권영우|작성시간07.08.14|조회수1,244 목록 댓글 0

제4절 데이터그램(Datagram) 프로그래밍

앞 절에서 살펴본 TCP 프로토콜의 소켓방식 데이터 전송은 클라이언트와 서버가 소켓으로 연결되어 논리적인 채널을 구성하기 때문에 데이터 전송의 정확성과 신뢰성이 보장된다. 그러나, 경우에 따라서는 상대적으로 신뢰성이 낮지만 빠르게 통신할 필요가 있을 수 있는데, 이 때 사용하는 것이 UDP (User Datagram Protocol) 프로토콜이다. UDP 프로토콜은 데이터그램이라는 데이터 패킷을 사용하는데, 데이터그램 패킷들은 서로 내용이 독립적이며 자체 내에 목적지에 대한 정보를 갖고 송신자로부터 수신자로 전공된다. 따라서, UDP는 메시지가 제대로 도착했는지 확인하는 확인 응답을 사용하지 않을 뿐만 아니라, 수신된 메시지의 순서를 맞추지 않으며, 기계간의 정보 흐름 속도를 제어하기 위한 피드백을 제공하지 않기 때문에, UDP 메시지는 손실되거나, 중복되거나, 비순서적으로 도착될 수 있다.

자바에서는 java.net 패키지에서 데이터그램 패킷을 생성하고 제어하기 위한 DatagramPacket 클래스와 데이터그램 패킷을 보내거나 받기 위한 데이터그램 소켓 기능을 제공해 주는 DatagramSocket 클래스를 제공한다.
 

4.1 TCP와 UDP의 차이점

    UDP 프로그래밍도 TCP 프로그래밍과 같이 네트워크를 위한 프로그래밍이기 때문에 통신을 위한 전체적인 구조는 유사하지만, 통신을 구현하는 세부적인 사항에서 약간의 차이를 갖고 있다.

    (1) 소켓의 종류

    앞에서 설명한 TCP 프로그래밍에서는 서버측에서 클라이언트의 요청에 응답하기 위한 ServerSocket과 클라이언트측에서 서버에 요청하며 그 응답을 처리하기 위한 Socket의 두가지로 구분되어 있음을 기억할 것이다.
    그러나 데이터그램 프로그래밍에서는 서버 소켓이 별도로 존재하지 않으며, 클라이언트 소켓에 해당하는 DatagramSocket 개체만이 있다. 이것은 UDP 프로그래밍은 비연결형(connectionless)이므로 서버와 클라이언트의 접속을 당당할 서버소켓이 필요없는 것이다. 따라서, 데이터그램 프로그래밍에서는 데이터그램 소켓이 클라이언트로부터 전송되는 데이터그램 패킷을 무조건적으로 읽고 쓴다.

    (2) 전달 데이터 유형

    TCP 프로그래밍(혹은 소켓 프로그래밍)에서 전달되는 데이터는 우리가 일상적인 프로그래밍에서 다루는 데이터와 동일한 유형으로서, 입출력스트림이 다룰 수 있는 데이터라면 TCP 프로그래밍에서도 전송이 가능하였다. 즉, 애플리케이션에서 출력스트림을 통해 데이터를 전송하면 하위 계층인 TCP/IP 계층을 통과하면서 패킷화되기 때문에, TCP 프로그래밍에서는 패킷에 대해 고려할 필요가 없이 프로토콜의 애플리케이션 계층에서만 프로그램을 작성하면 되었다.
    그러나 데이터그램 프로그래밍에서는 전송할 데이터를 데이터그램 패킷으로 변환한 후에 입출력스트림을 통해 전송한다. 여기서, 자바의 데이터그램 패킷은 순수한 데이터그램 패킷이 아닌 IP 패킷의 특성도 포함하고 있기 때문에, 자바의 데이터그램 프로그래밍은 TCP/IP 프로토콜의 애플리케이션 계층, 전송계층, 그리고 네트워크 계층까지 관여한다.
     

    4.2 데이터그램 프로그래밍 클래스

      자바의 java.net 패키지에서는 데이터그램 프로그래밍을 위해서 DatagramSocket 과 DatagramPacket, 그리고 MulticastSocket을 제공한다.

      (1) DatagramPacket 클래스

      DatagramPacket 클래스는 데이터그램을 사용할 수 있도록 기능을 제공해 주며, 데이터그램 패킷은 비연결 패킷 전송 서비스(connectionless packet delivery service)를 구현하기 위해 사용된다. 메시지는 패킷 내에 포함되어 있는 정보에 기반하여 하나의 호스트에서 다른 호스트로 라우팅(routed)된다. 따라서, 한 호스트에서 다른 호스트로 전송된 여러 개의 패킷(multiple packet)은 서로 다르게 라우팅 될 것이며, 원래의 순서와 관계없이 도착될 수 있다. 데이터그램 패킷은 다음과 같이 생성할 수 있다.

        DatagramPacket(byte[] buf, int length)
        DatagramPacket(byte[] buf, int offset, int length)
        DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)

      이들 생성자는 IP 어드레스를 address 로 갖는 기계의 포트번호 port 로 전송할 데이터그램 패킷을 생성하는데, 이 패킷의 기본 단위는 byte 단위로, 패킷 데이터는 byte형 배열 변수인 buf 안에 저장된 바이트이다. 여기서, length 는 이 버퍼에서 읽어들일 데이터 길이를 바이트 단위로 지정하는 것으로, 데이터 버퍼 buf의 길이를 초과할 수 없다.

      다음으로 데이터그램패킷 클래스로 생성한 객체에 적용할 수 있는 메소드들은 다음과 같다.

      • InetAddress getAddress() // 데이터그램이 송수신 호스트의 IP 주소를 얻음.
      • byte[] getData() // 데이터를 얻음
      • int getLength() // 데이터의 크기
      • int getOffset() // 데이터의 offset
      • int getPort() // 원격 호스트의 포트 번호
      • void setAddress(InetAddress iaddr) // IP 주소 설정
      • void setData(byte[] buf) // 데이터 버퍼 설정
      • void setData(byte[] buf, int offset, int length) // 데이터 버퍼 설정
      • void setLength(int length) // 패킷 크기 설정
      • void setPort(int iport) // 포트 번호를 설정
         

       (2) DatagramSocket 클래스

      DatagramSocket 클래스는 데이터그램 패킷을 보내거나 받기 위한 데이터그램 소켓 기능을 제공해 주는 클래스로서, 패킷의 송수신 서비스를 위한 포트이다. 데이터그램 소켓에서 보내지거나 또는 데이터그램 소켓이 받아들인 각각의 패킷은개별적으로 경로를 설정하여 보내진다. 데이터그램 소켓 클래스의 생성자는 다음과 같다.

        DatagramSocket()
        DatagramSocket(int port)
        DatagramSocket(int port, InetAddress address)

      생성자에서 address와 port를 지정하면 해당하는 IP 주소와 포트를 사용하여 데이터그램 소켓을 생성한다. 여기서, address를 지정하지 않으면 로컬호스트에 데이터그램소켓을 생성하며, port를 지정하지 않은 경우에는 사용가능한 임의의 포트를 이용한다.

      다음으로 데이터그램 소켓 클래스로 생성한 객체에 적용할 수 있는 메소드들은 다음과 같다.

      • void close() // 소켓을 닫음
      • void connect(InetAddress address, int port) // 원격 소켓에 연결
      • void disconnect() // 연결해제
      • InetAddress getInetAddress() // 소켓이 연결되어 있는 IP 주소
      • InetAddress getLocalAddress() // 소켓에 연결된 로컬 IP 주소
      • int getLocalPort() // 소켓에 연결된 로컬 포트
      • int getPort() // 소켓이 연결되어 있는 원격 포트
      • int getReceiveBufferSize() // 소켓의 입력(수신) 버퍼의 크기인 SO_RCVBUF 값
      • int getSendBufferSize() // 출력(송신) 버퍼의 크기인 SO_SNDBUF 값
      • int getSoTimeout() // SO_TIMEOUT에 설정되어 있는 값
      • void receive(DatagramPacket p) // 데이터그램 패킷 수신
      • void send(DatagramPacket p) // 데이터그램 패킷 송신
      • void setReceiveBufferSize(int size) // 입력(수신) 버퍼의 크기인 SO_RCVBUF 설정
      • void setSendBufferSize(int size) // 출력(송신) 버퍼의 크기인 SO_ SNDBUF 값 설정
      • void setSoTimeout(int timeout) // SO_TIMEOUT의 값을 주어진 시간(밀리초)으로 설정

       

      (3) 데이터의 송수신 방식

      데이터그램을 이용한 통신방식에서 서버와 클라이언트가 연결되어 데이터를 주고 받기까지의 과정을 순서에 따라 나타내면 다음과 같다. 데이터그램 소켓은 TCP 방식과는 달리 서버와 클라이언트가 동일하게 사용하며, 먼저 서버측에서 소켓을 생성하여 대기하면 클라이언트가 소켓을 생성하여 데이터를 전송한다.

      순서
      Datagram Server
      Datagram Client
      1
      데이터그램 소켓 생성 및 연결  
      2
      입력 데이터그램 패킷 생성   
      3
      대기 데이터그램 소켓 생성 및 연결
      4
      대기 출력 데이터그램 패킷 생성 및 송신
      5
      입력 데이터그램 패킷 받기 입력 데이터그램 패킷 생성
      6
      응답 내용 처리 대기
      7
      출력 데이터그램 패킷 생성 및 송신 대기
      8
        입력 데이터그램 패킷 받기
      9
        응답 내용 처리 및 마치기

      1. 서버는 클라이언트로부터 요청을 받고 그에 대해 응답을 하기 위한 데이터그램 소켓을 하여 특정 포트에 연결한다.
      2. 서버는 클라이언트로부터 오는 요청 내용을 저장할 입력 데이터그램 패킷을 생성한 뒤 클라이언트로부터 요청이 오기를 기다리며 대기한다.
      3. 클라이언트 프로그램을 실행하면 서버에서와 마찬가지로 데이터그램 소켓을 하여 특정 포트에 연결한다.
      4. 클라이언트는 서버에 요청을 보내기 위한 출력 데이터그램 패킷을 생성한 뒤 서버에게 송신한다.
      5. 서버는 클라이언트가 보낸 데이터그램 패킷을 받아들인다. 여기서, 서버는 입력 데이터그램 패킷을 생성하고 대기하였는데, 이 입력 데이터그램 패킷은 아무런 내용이 없는 빈 패킷으로서 이 패킷이 클라이언트가 보낸 데이터그램 패킷으로 대치된다. 따라서 서버 자신이 생성한 입력 데이터그램 패킷을 받는 것 자체가 곧 클라이언트가 보낸 데이터그램 패킷을 받는 것과 동일한 효과를 나타낸다.
        클라이언트도 서버가 보낸 응답을 받기 위한 입력 데이터그램 패킷을 생성하고 대기한다.
      6. 서버는 클라이언트의 요청에 대해 응답할 내용을 처리한다.
      7. 서버는 출력 데이터그램 패킷을 생성하여 클라이언트에게 송신한다.
      8. 클라이언트는 서버가 보낸 응답 데이터그램 패킷을 수신하는데, 이 과정은 서버가 입력 데이터그램 패킷을 수신하는 것과 동일한 방법으로 수행된다.
      9. 끝으로, 클라이언트는 서버로부터의 응답 내용을 화면에 출력하는 등의 처리를 한 후 소켓을 끊는다.
         

      (4) 데이터그램 예제 프로그램

      데이터그램의 개념을 보다 쉽게 이해할 수 있도록 클라이언트가 서버에게 메시지를 보내면, 서버가 수신한 메시지를 그대로 다시 클라이언트에게 보내주는 Echo 기능을 수행하는간단한 프로그램을 작성해 보고자 한다. 이 프로그램은 앞의 소켓 프로그램에서 작성한 것과 동일한 기능을 수행하기 때문에 비교해서 공부하면 TCP와 UDP의 차이를 이해하는데 도움이 될 것이다.

      먼저 서버측 프로그램을 작성하면 다음과 같다. 서버는 데이터그램 소켓과 패킷을 생성한 후 클라이언트로부터 전송되는 데이터를 받아서 received라는 문자열에 넣음으로서 수신과정이 끝난다. 다음으로 이 문자열을 다시 바이트 배열로 전환하여 원격 호스트의 주소로 원래의 포트를 통해 전송한다.

      [예제 - Server측 프로그램의 예]

        import java.io.*;
        import java.net.*;
        public class ExampleServer {
           public static void main(String[] args) {
              DatagramPacket packet = null;
              byte[] b = new byte[256];
              try {
                 DatagramSocket socket = new DatagramSocket(4444);
                 for (;;) {
                     packet = new DatagramPacket(b, b.length);
                     // 패킷을 받아서 데이터를 received 문자열에 넣음.
                     socket.receive(packet);
                     String received = new String(packet.getData());

                     // 데이터를 바이트배열로 전환하여 패킷으로 다시 보냄.
                     InetAddress address = packet.getAddress();
                     int port = packet.getPort();
                     b = received.getBytes();
                     packet = new DatagramPacket(b, b.length, address, port);
                     socket.send(packet);
                 }
              } catch(IOException ex) {
                  ex.printStackTrace();
              }
           }
        }

      다음으로 클라이언트측 프로그램을 작성하면 다음과 같다. 여기서는 키보드를 통해 지속적을 입력하는 문자열을 서버에 보내어 Echo가 되도록 하였으므로, 클라이언트 프로그램의 수행을 종료하기 위해서는 Ctrl-Z를 입력해야 한다. 또한, host의 문자열을 localhost로 지정하였는데, 이것은 로컬에 존재하는 동일한 컴퓨터를 서버와 클라이언트로 사용하겠다는 의미가 된다.

      [예제 - Client측 프로그램의 예]

        import java.io.*;
        import java.net.*;
        public class ExampleClient {
           public static void main(String[] args) {
              byte[] b = new byte[256];
              String host = "localhost";
              String send = null;
              DatagramPacket packet = null;
              BufferedReader  in;
              try {
                 DatagramSocket socket = new DatagramSocket();
                 InetAddress address = InetAddress.getByName(host);

                 in = new BufferedReader (new InputStreamReader(System.in));
                 System.out.print("송신: ");
                 while ((send = in.readLine()) != null) {  // 종료시에는 Ctrl-Z 입력
                    // 문자열을 바이트배열로 전환한 후 포트 4444로 전송한다.
                    b = send.getBytes(); 
                    packet = new DatagramPacket(b, b.length, address, 4444);
                    socket.send(packet);

                    // 패킷을 수신하여 문자열로 전환한 후 화면에 출력한다.
                    packet = new DatagramPacket(b, b.length);
                    socket.receive(packet);
                    String received = new String(packet.getData());             System.out.println("수신: " + received);
                    System.out.print("송신: ");
                 }
                 socket.close();
              } catch(IOException ex) {
                  ex.printStackTrace();
              }
           }
        }

      위와 같이 서버와 클라이언트 프로그램의 작성이 끝나면 먼저 서버 프로그램을 실행시킨 후에 클라이언트 프로그램을 실행시킨다. 프로그램의 수행된 후 키보드를 이용하여 임의의 문자열을 입력하고 엔터를 치면, 동일한 문자열이 화면에 나타나는데, 이것은 서버가 데이터그램 통신을 통해 보내준 문자열이다. 다음 그림에서 그 결과를 확인하기 바란다.

      이 그림은 클라이언트 측의 화면으로서, 위의 프로그램에서 서버측에는 아무런 메시지도 나타나지 않도록 했기 때문에 서버에는 나타나지 않는다. 또한 클라이언트 프로그램을 종료시키더라도 서버측의 프로그램은 강제적으로 종료시키기 전까지는 for (;;) 무한 루프를 돌면서 클라이언트의 요청을 기다린다.

       

    4.3 멀티 캐스트 (MulticastSocket)

      자바언어에서 사용하고 있는 멀티캐스트라는 단어는 일반적으로는 브로트캐스트(broadcast), 즉 방송이라는 단어로 사용된다. 이것은 KBS, MBC, SBS, EBS 등 우리나라 텔레비젼 방송사의 이름에 포함되어 있는 B(boradcast)라는 글자와 동일한 것으로 멀티캐스트의 개념을 이해하기 위해서는 앞에서 살펴본 1:1 통신과 방송의 차이를 알아야 할 것이다.

      방송의 가장 큰 특성은 데이터의 수신자가 불특정 다수라는 것과 수신자의 선택에 따라 데이터의 수신을 결정할 수 있다는 것이다. 즉, 우리가 텔레비젼 방송을 시청할 때 많은 방송이 유무선 전송매체를 통해 전송되지만 우리가 채널을 선택한 방송만이 화면에 나타나게 되는 것이다. 하지만, 특정 방송을 수신하기로 결정한 경우에라도 해당 수신자가 송신자에게 방송의 내용을 변경할 것을 요청하는 등의 상호작용적 통신은 불가능하며 일방적으로 통신이 이루어질 뿐이다.

      (1) 자바의 멀티캐스트 방식

      자바언어에서는 데이터를 송신하고자 하는 서버가 특정 채널 IP 주소 및 포트를 통해 데이터그램 패킷을 송신하면, 이를 수신하고자 하는 클라이언트는 해당 채널 IP 주소와 포트에 연결하여 멀티캐스트 데이터그램 패킷을 수신하는 간단한 방식으로 구성되어 있다. 멀티캐스트를 수신하기 위해서는 수신기를 켜고 채널을 맞추어야 하는 것과 같이 자바에서는 멀티캐스트 소켓(MulticastSocket)을 생성하여 멀티캐스트 채널 포트에 연결한다.

      여기서 클라이언트가 서버의 채널에 맞추는 것은 서버가 개설한 멀티캐스트 채널 IP 주소와 포트의 번호를 일치시켜서 방송에 참여하는 것이다. 여기서, 채널의 포트번호를 맞추는 것은 멀티캐스트 소켓을 생성하면서 이루어지기 때문에 방송에 참여하기만 하면되는데, 이것은 MulticastSocket 클래스의 joinGroup() 메소드를 이용한다.

      방송의 수신을 모두 끝내면 close() 메소드를 이용하여 방송의 수신을 종료한다.

       

      (2) MulticastSocket 클래스

      MulticastSocket 클래스는 멀티캐스트 데이터그램 소켓을 위한 클래스로서 IP 멀티캐스트 패킷을 송신 또는 수신하기 위한 기능을 제공해 준다. 즉, MulticastSocket 객체는 인터넷에서 멀티캐스트 그룹에 속한 모든 클라이언트들에게 송신하기 위한 기능이 포함된 DatagramSocket 객체라 할 수 있다. 여기서, 멀티캐스트 그룹이란 IP 주소 클래스 중 D 클래스, 224.0.0.0에서 239.255.255.255 까지의 IP 주소 범위, 그리고, 표준 UDP 포트 번호를 이용하여 나타낼 수 있다. 이 때, 요구된 포트를 갖는 MulticastSocket 객체를 생성한 후 joinGroup(InetAddress groupAddr) 메소드를 호출함으로써 멀티캐스트 그룹에 연결할 수 있다. 그런데, IP 멀티캐스트 주소 중 224.0.0.0은 예약되어 있고, 224.0.01은 IP 멀티캐스트에 참여하는 모든 호스트와 라우터를 포함하는 모든 호스트 그룹에 영구히 할당되어 있으므로 사용할 수 없다.

      멀티캐스트소켓 클래스로부터 객체를 생성하는 방법은 다음과 같다. 멀티캐스트 소켓을 생성하기 위해서는 다음과 같이 연결할 포트를 지정해야 하는데, 이 번호는 브로드캐스트 서버가 개설한 채널 포트번호와 일치해야 한다.

          public MulticastSocket(int port) throws IOException

      이 소켓을 생성할 때 애플리케이션에서 보안관리자를 설치해두었으면, 데이터그램 소켓을 생성하기 전에 인자를 0으로 지정한 checkListen(0) 메쏘드를 호출하여 보안 검사를 한 뒤 문제가 없을 때 이 작업을 진행한다. 그러나, 보안상의 문제가 발생한 경우에는 SecurityException 예외가 발생한다.

      다음으로  멀티캐스트 소켓으로 생성한 객체에 적용되는 메소드들은 다음과 같다.

      • public void joinGroup(InetAddress channel) throws IOException
        지정한 IP 주소의 멀티캐스트 채널 그룹 channel에 대해 현재 MulticastSocket 객체를 멤버로 가입하며, 이 채널을 통해 멀티캐스트 데이터그램 패킷을 받을 수 있다.
      • public void leaveGroup(InetAddress channel) throws IOException
        지정한 IP 주소의 멀티캐스트 채널 그룹 channel에서 현재 MulticastSocket 개체를 제외시킨다. 여기서, 현재 MulticastSocket 객체를 채널 그룹에 가입시키거나 떠날 때 애플리케이션에서 보안관리자를 설치해두었으면, 이 보안관리자는 먼저 채널 IP 어드레스 channel을 인자로 한 checkMulticast(channel) 메소드를 호출하여 보안 검사를 한 뒤 문제가 없으면 후속 작업을 진행한다.
      • public void setInterface(InetAddress newCh) throws SocketException
        MulticastSocket 의 멀티캐스트 채널 그룹을 새로운 그룹 newCh로 바꿉니다.  

       

      (3) 멀티캐스트 프로그램의 예

      다음은 멀티캐스트의 개념을 이해하는데 도움이 되도록 간단한 멀티캐스트 프로그램을 소개하고자 한다. 이 프로그램에서 서버는 쓰레드를 이용하여 지속적으로 문자열 변수인 msg의 문자열을 접속한 클라이언트들에게 송신한다. 따라서, 이 문자열을 변경하는 메소드를 추가하면 뉴스를 제공하는 프로그램을 간단히 작성할 수 있을 것이다.

      먼저, 서버측 프로그램은 다음과 같다. 여기서, 소켓은 데이터그램소켓을 이용하며, 방송을 중계하는 중계소의 IP 주소로 230.0.0.1 를 설정했으며, 이에 대응하는InetAddress 개체를 만들어 사용하였다.

      [예제 - Multicast Server측 프로그램의 예]

        import java.io.*;
        import java.net.*;
        import java.util.*;
        public class ExampleCastServer extends Thread {
          DatagramSocket socket = null;
          DatagramPacket packet = null;
          InetAddress channel =null;
          int port = 5555;
          String address = "230.0.0.1";
          boolean onAir = true;

          // 생성자
          public ExampleCastServer() throws IOException {
            super("사이버유 방송");
            socket = new DatagramSocket(port);
          }

          // 뉴스를 읽는다.
          protected String getNews() {
            String msg = "여기는 사이버유 방송입니다";
            return msg;
          }

          // 쓰레드의 메소드 구현
          public void run() {
            byte[] b = new byte[100];
            while (onAir) { // onAir가 false가 될 때까지 지속적으로 반복
              try {
                b = getNews().getBytes(); // 바이트 배열로 만듦
                channel = InetAddress.getByName(address);
                packet = new DatagramPacket(b, b.length, channel, port);
                socket.send(packet);  // 패킷 전송
                try {
                  sleep(2000); // 일정시간(밀리초) 기다렸다가 다시 보냄.
                } catch (InterruptedException e) { }
              } catch (IOException e) {
                  e.printStackTrace();
              } 
            }
            socket.close();
          }

          public static void main(String[] args) throws java.io.IOException {
            new ExampleCastServer().start();
          }
        }

       

      다음으로 클라이언트측 프로그램을 살펴보면 다음과 같다. 여기서 데이터그램 패킷을 설정하는 방법은 위에서 소개한 서버의 경우와 동일하며, 수신된 데이터를 받아들이기 위해서는 getData() 메소드를 이용한다.

      [예제 - Multicast Server측 프로그램의 예]

        import java.io.*;
        import java.net.*;
        import java.util.*;
        public class ExampleCastClient {
          MulticastSocket receiver = null;
          DatagramPacket packet = null;
          InetAddress channel =null;
          int port = 5555;
          String address = "230.0.0.1";
          byte[] b = new byte[100];

          public ExampleCastClient () {
             try {
                receiver = new MulticastSocket(port);
                channel = InetAddress.getByName(address);
                packet = new DatagramPacket(b, b.length);
                receiver.joinGroup(channel);
                for (int i=0; i<3; i++) {
                   receiver.receive(packet);
                   String notice = new String(packet.getData());
                   System.out.println(notice);
                }
                receiver.leaveGroup(channel);
                receiver.close();
             } catch (IOException e) {
                e.printStackTrace();
             } 
          }

           public static void main(String[] args) throws IOException {
             new ExampleCastClient();
           }
        }

       

       

      위에서 서버측 프로그램은 동일한 메시지를 2초마다 한번씩 송신하며, 클라이언트측 프로그램은 서버로부터 3회에 걸쳐 데이터를 수신하여 화면에 출력한다. 서버측 프로그램에 대해서는 새로운 공지사항을 올릴 수 있도록 수정하고, 클라이언트측 프로그램에서는 내용이 바뀔 때만 화면에 출력하도록 한다면 좀 더 실용적인 프로그램을 작성할 수 있을 것이다.

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
맨위로

카페 검색

카페 검색어 입력폼