먼티 캐스트 방식의 데이터 전송은 UDP를 기반으로 하는데, 하나의 목적지가 아닌 특정 그룹에 해당하는 다수의 호스트에게 데이터를 전송한다. 한번만 전송하더라도, 라우터들에 의해 복사되어 모두에게 전송된다.
TTL
TTL은 **'패킷을 얼마나 멀리 전달할 것인가'
**를 결정하는 주 요소가 된다. 라우터를 거칠때마다 1씩 감소되어 0이되면 해당 패킷이 소멸되며, 너무 크게 설정하면 네트워크 트래픽에 좋지 않은 영향을 줄 수 있다. TTL을 설정하는 법은 setsockopt 함수를 이용하여 구성할 수 있다.
int send_sock;
int time_to_live = 64;
send_sock=socket(PF_INET, SOCK_DGRAM< 0); // UDP 소켓
setsockpet(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void*)&time_to_live, sizeof(time_to_live);
그룹 가입과 관련된 프로토콜의 레벨은 IPPROTO_IP이고, 옵션의 이름은 IP_ADD_MEMBERSHIP이다. 구현은 다음과 같다.
int main(int argc, char *argv[])
{
int recv_sock;
struct sockaddr_in adr;
struct ip_mreq join_adr;
recv_sock=socket(PF_INET, SOCK_DGRAM, 0);
...;
join_adr.imr_multiaddr.s_addr=inet_addr(argv[1]); // 가입할 그룹 주소
join_adr.imr_interface.s_addr=htonl(INADDR_ANY); // 본인의 주소
setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));
while(1)
{
str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
if(str_len<0) { break; }
buf[str_len]=0;
fputs(buf, stdout);
}
close(recv_sock);
return 0;
}
Sender은 파일에 저장된 뉴스 정보를 AAA 그룹으로 broadcasting하고, receiver은 이 정보를 수신하는 것을 바탕으로 구현하였다.
news_sender.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define TTL 64
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int send_sock;
struct sockaddr_in mul_adr;
int time_live=TTL;
FILE *fp;
char buf[BUF_SIZE];
if(argc!=3){
printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);
exit(1);
}
send_sock=socket(PF_INET, SOCK_DGRAM, 0);
memset(&mul_adr, 0, sizeof(mul_adr));
mul_adr.sin_family=AF_INET;
mul_adr.sin_addr.s_addr=inet_addr(argv[1]); // Multicast IP
mul_adr.sin_port=htons(atoi(argv[2])); // Multicast Port
setsockopt(send_sock, IPPROTO_IP,
IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live));
if((fp=fopen("news.txt", "r"))==NULL)
error_handling("fopen() error");
while(!feof(fp)) /* Broadcasting */
{
fgets(buf, BUF_SIZE, fp);
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&mul_adr, sizeof(mul_adr));
sleep(2);
}
fclose(fp);
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
Sender는 일반 UDP 소켓 프로그램과 차이가 크지 않다. UDP 소켓을 생성하고, IP주소를 멀티캐스트 주소로 설정한 뒤 TTL 정보를 지정하여 sendto 함수를 통해 전송한다.
news_receiver.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int recv_sock;
int str_len;
char buf[BUF_SIZE];
struct sockaddr_in adr;
struct ip_mreq join_adr;
if(argc!=3) {
printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);
exit(1);
}
recv_sock=socket(PF_INET, SOCK_DGRAM, 0);
memset(&adr, 0, sizeof(adr));
adr.sin_family=AF_INET;
adr.sin_addr.s_addr=htonl(INADDR_ANY);
adr.sin_port=htons(atoi(argv[2]));
if(bind(recv_sock, (struct sockaddr*) &adr, sizeof(adr))==-1)
error_handling("bind() error");
join_adr.imr_multiaddr.s_addr=inet_addr(argv[1]);
join_adr.imr_interface.s_addr=htonl(INADDR_ANY);
setsockopt(recv_sock, IPPROTO_IP,
IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));
while(1)
{
str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
if(str_len<0)
break;
buf[str_len]=0;
fputs(buf, stdout);
}
close(recv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
ip_mreg형 변수을 머티캐스트 그룹 IP주소와 그룹에 가입할 호스트의 IP주소를 초기화한 후, IP_ADD_MEMBERSHIP을 이용해서 멀티캐스트 그룹에 가입한다. 그 후 recvfrom 함수호출을 통해 멀티캐스트 데이터를 수신한다.
브로드캐스트는 동일한 네트워크 내에 존재하는 호스트에게 데이터를 전송하기 위한 방법
이다. 데이터를 전송하는 대상이 호스트가 아닌 네트워크 이기 때문에 네트워크에 연결된 호스트에 모두 전달된다. 데이터 전송 시 사용되는 IP주소의 형태에 따라서 다음과 같이 두 가지 형태로 구분이 된다.
- Directed 브로드캐스트
- 특정 지역의 네트워크에 연결된 모든 호스트에게 데이터를 전송하기 위한 수단.
- 192.34.24인 네트워크의 모든 호스트에게 데이터를 전송하려면 192.12.34.255로 전송하면 됨.
- Local 브로드캐스트
- Local 브로드캐스트를 위해서는 255.255.255.255라는 IP주소가 특별히 예약되어 있다.
- 네트워크 주소가 192.32.24인 네트워크에 연결되어 있는 호스트가 IP주소 255.255.255.255로 전달하면 192.32.24로 시작하는 IP주소의 모든 호스트에게 데이터 전달
int send_sock;
int bcast = 1; // 브로드캐스트 ON
send_sock=socket(PF_INET, SOCK_DGRAM, 0);
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void*)&bcast, sizeof(bcast));
news_sender_brd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int send_sock;
struct sockaddr_in broad_adr;
FILE *fp;
char buf[BUF_SIZE];
int so_brd=1;
if(argc!=3) {
printf("Usage : %s <Boradcast IP> <PORT>\n", argv[0]);
exit(1);
}
send_sock=socket(PF_INET, SOCK_DGRAM, 0);
memset(&broad_adr, 0, sizeof(broad_adr));
broad_adr.sin_family=AF_INET;
broad_adr.sin_addr.s_addr=inet_addr(argv[1]);
broad_adr.sin_port=htons(atoi(argv[2]));
setsockopt(send_sock, SOL_SOCKET,
SO_BROADCAST, (void*)&so_brd, sizeof(so_brd));
// UDP 소켓을 브로드캐스트 기반 데이터 전송을 하도록 옵션 정보 변경
if((fp=fopen("news.txt", "r"))==NULL)
error_handling("fopen() error");
while(!feof(fp))
{
fgets(buf, BUF_SIZE, fp);
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&broad_adr, sizeof(broad_adr));
sleep(2);
}
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
news_receiver_brd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int recv_sock;
struct sockaddr_in adr;
int str_len;
char buf[BUF_SIZE];
if(argc!=2) {
printf("Usage : %s <PORT>\n", argv[0]);
exit(1);
}
recv_sock=socket(PF_INET, SOCK_DGRAM, 0);
memset(&adr, 0, sizeof(adr));
adr.sin_family=AF_INET;
adr.sin_addr.s_addr=htonl(INADDR_ANY);
adr.sin_port=htons(atoi(argv[1]));
if(bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr))==-1)
error_handling("bind() error");
while(1)
{
str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
if(str_len<0)
break;
buf[str_len]=0;
fputs(buf, stdout);
}
close(recv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}