|
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의 길이를 초과할 수 없다.
다음으로 데이터그램패킷 클래스로 생성한 객체에 적용할 수 있는 메소드들은 다음과 같다.
(2) DatagramSocket 클래스
DatagramSocket 클래스는 데이터그램 패킷을 보내거나 받기 위한 데이터그램 소켓 기능을 제공해 주는 클래스로서, 패킷의 송수신 서비스를 위한 포트이다. 데이터그램 소켓에서 보내지거나 또는 데이터그램 소켓이 받아들인 각각의 패킷은개별적으로 경로를 설정하여 보내진다. 데이터그램 소켓 클래스의 생성자는 다음과 같다.
DatagramSocket()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress address)
생성자에서 address와 port를 지정하면 해당하는 IP 주소와 포트를 사용하여 데이터그램 소켓을 생성한다. 여기서, address를 지정하지 않으면 로컬호스트에 데이터그램소켓을 생성하며, port를 지정하지 않은 경우에는 사용가능한 임의의 포트를 이용한다.
다음으로 데이터그램 소켓 클래스로 생성한 객체에 적용할 수 있는 메소드들은 다음과 같다.
(3) 데이터의 송수신 방식
데이터그램을 이용한 통신방식에서 서버와 클라이언트가 연결되어 데이터를 주고 받기까지의 과정을 순서에 따라 나타내면 다음과 같다. 데이터그램 소켓은 TCP 방식과는 달리 서버와 클라이언트가 동일하게 사용하며, 먼저 서버측에서 소켓을 생성하여 대기하면 클라이언트가 소켓을 생성하여 데이터를 전송한다.
|
|
|
|
데이터그램 소켓 생성 및 연결 | |
|
입력 데이터그램 패킷 생성 | |
|
대기 | 데이터그램 소켓 생성 및 연결 |
|
대기 | 출력 데이터그램 패킷 생성 및 송신 |
|
입력 데이터그램 패킷 받기 | 입력 데이터그램 패킷 생성 |
|
응답 내용 처리 | 대기 |
|
출력 데이터그램 패킷 생성 및 송신 | 대기 |
|
입력 데이터그램 패킷 받기 | |
|
응답 내용 처리 및 마치기 |
(4) 데이터그램 예제 프로그램
데이터그램의 개념을 보다 쉽게 이해할 수 있도록 클라이언트가 서버에게 메시지를 보내면, 서버가 수신한 메시지를 그대로 다시 클라이언트에게 보내주는 Echo 기능을 수행하는간단한 프로그램을 작성해 보고자 한다. 이 프로그램은 앞의 소켓 프로그램에서 작성한 것과 동일한 기능을 수행하기 때문에 비교해서 공부하면 TCP와 UDP의 차이를 이해하는데 도움이 될 것이다.
먼저 서버측 프로그램을 작성하면 다음과 같다. 서버는 데이터그램 소켓과 패킷을 생성한 후 클라이언트로부터 전송되는 데이터를 받아서 received라는 문자열에 넣음으로서 수신과정이 끝난다. 다음으로 이 문자열을 다시 바이트 배열로 전환하여 원격 호스트의 주소로 원래의 포트를 통해 전송한다.
[예제 - Server측 프로그램의 예] import java.io.*; |
다음으로 클라이언트측 프로그램을 작성하면 다음과 같다. 여기서는 키보드를 통해 지속적을 입력하는 문자열을 서버에 보내어 Echo가 되도록 하였으므로, 클라이언트 프로그램의 수행을 종료하기 위해서는 Ctrl-Z를 입력해야 한다. 또한, host의 문자열을 localhost로 지정하였는데, 이것은 로컬에 존재하는 동일한 컴퓨터를 서버와 클라이언트로 사용하겠다는 의미가 된다.
[예제 - Client측 프로그램의 예] import java.io.*; |
위와 같이 서버와 클라이언트 프로그램의 작성이 끝나면 먼저 서버 프로그램을 실행시킨 후에 클라이언트 프로그램을 실행시킨다. 프로그램의 수행된 후 키보드를 이용하여 임의의 문자열을 입력하고 엔터를 치면, 동일한 문자열이 화면에 나타나는데, 이것은 서버가 데이터그램 통신을 통해 보내준 문자열이다. 다음 그림에서 그 결과를 확인하기 바란다.
이 그림은 클라이언트 측의 화면으로서, 위의 프로그램에서 서버측에는 아무런 메시지도 나타나지 않도록 했기 때문에 서버에는 나타나지 않는다. 또한 클라이언트 프로그램을 종료시키더라도 서버측의 프로그램은 강제적으로 종료시키기 전까지는 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 예외가 발생한다.
다음으로 멀티캐스트 소켓으로 생성한 객체에 적용되는 메소드들은 다음과 같다.
(3) 멀티캐스트 프로그램의 예
다음은 멀티캐스트의 개념을 이해하는데 도움이 되도록 간단한 멀티캐스트 프로그램을 소개하고자 한다. 이 프로그램에서 서버는 쓰레드를 이용하여 지속적으로 문자열 변수인 msg의 문자열을 접속한 클라이언트들에게 송신한다. 따라서, 이 문자열을 변경하는 메소드를 추가하면 뉴스를 제공하는 프로그램을 간단히 작성할 수 있을 것이다.
먼저, 서버측 프로그램은 다음과 같다. 여기서, 소켓은 데이터그램소켓을 이용하며, 방송을 중계하는 중계소의 IP 주소로 230.0.0.1 를 설정했으며, 이에 대응하는InetAddress 개체를 만들어 사용하였다.
[예제 - Multicast Server측 프로그램의 예] import java.io.*; |
다음으로 클라이언트측 프로그램을 살펴보면 다음과 같다. 여기서 데이터그램 패킷을 설정하는 방법은 위에서 소개한 서버의 경우와 동일하며, 수신된 데이터를 받아들이기 위해서는 getData() 메소드를 이용한다.
[예제 - Multicast Server측 프로그램의 예] import java.io.*; |
위에서 서버측 프로그램은 동일한 메시지를 2초마다 한번씩 송신하며, 클라이언트측 프로그램은 서버로부터 3회에 걸쳐 데이터를 수신하여 화면에 출력한다. 서버측 프로그램에 대해서는 새로운 공지사항을 올릴 수 있도록 수정하고, 클라이언트측 프로그램에서는 내용이 바뀔 때만 화면에 출력하도록 한다면 좀 더 실용적인 프로그램을 작성할 수 있을 것이다.