728x90
반응형
SMALL
멀티캐스트
- 1 : n 통신 (point-to-multipoint)
- 하나의 발신지로부터 특정 그룹에게로 데이터 전송
- 발신지에서 하나의 패킷을 보내고, 네트워크(주로 라우터)쪽에서 이의 복사본을 여러 곳에 보냄
- UDP 사용
- 실시간 다중 수신 응용에 주로 사용 ex) 영상회의, IPTV, game 등
장점
- 송신자는 한 번의 전송을 통하여 여러 발신자들에게 데이터를 전송하므로 네트워크 자원 낭비를 막을 수 있음
- 그룹에 속하지 않은 호스트는 영향을 받지 않으므로 전체 트래픽 증가가 브로드캐스트에 비하여 감소
단점
- 라우터가 멀티캐스트를 지원해야 가능함
멀티캐스트 주소
224.0.0.0 ~ 239.255.255.255 범위를 갖는 클래스 D의 IP를 사용함
멀티캐스트 특징
- 그룹 가입과 탈퇴가 자유롭고 그룹 구성원 모두가 평등함
- 멀티캐스트 데이터를 받으려면 그룹에 가입해야 함
- 멀티캐스트 데이터를 보내려고 그룹에 가입할 필요 없음
- 데이터의 수신을 위해서 IGMP(internet group management protocol) 프로토콜 사용
멀티캐스트 데이터 전송
- 그룹에 속한 구성원이 데이터를 보내는 경우
멀티캐스트 실습 - receiver
235.7.8.9
#include "../../common.h"
#define MULTICASTIP "235.7.8.9"
#define SERVERPORT 9000
#define BUFSIZE 512
int main(int argc, char* argv[])
{
int retval = -1;
// initialize winsock
WSADATA wsa;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsa))
return 1;
// create socket
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (INVALID_SOCKET == sock)
err_quit("socket()");
// SO_REUSEADDR 설정
DWORD optval = 1;
retval = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(optval));
if (SOCKET_ERROR == retval)
err_quit("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
// bind socket
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(SERVERPORT);
retval = bind(sock, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (retval == SOCKET_ERROR)
err_quit("bind()");
printf("I'm running!!!\n");
// 멀티캐스트 그룹 가입 IP_ADD_MEMBERSHIP
struct ip_mreq mreq;
inet_pton(AF_INET, MULTICASTIP, &mreq.imr_multiaddr);
mreq.imr_interface.S_un.S_addr = htonl(INADDR_ANY);
retval = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq));
if (retval == SOCKET_ERROR)
err_quit("setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP)");
// data communication
struct sockaddr_in clientaddr;
int addrlen;
char buf[BUFSIZE + 1];
while (1)
{
// accept()
addrlen = sizeof(clientaddr);
retval = recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr*)&clientaddr, &addrlen);
// recv error
if (SOCKET_ERROR == retval)
{
err_display("recvfrom()");
break;
}
// print the received data
buf[retval] = '\0';
char addr[INET_ADDRSTRLEN] = { 0, };
inet_ntop(AF_INET, &clientaddr.sin_addr, addr, sizeof(addr));
printf("[UDP/%s:%d] %s\n", addr, ntohs(clientaddr.sin_port), buf);
// send data
}
// 멀티캐스트 그룹 탈퇴 IP_DROP_MEMBERSHIP
retval = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq));
if (retval == SOCKET_ERROR)
err_quit("setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP)");
// close socket
closesocket(sock);
// close winsock
WSACleanup();
return 0;
}
멀티캐스트 실습 - sender
235.7.8.9
#include "../../common.h"
#define MULTICASTIP "235.7.8.9"
#define SERVERPORT 9000
#define BUFSIZE 512
int main(int argc, char* argv[])
{
int retval = -1;
// initialize winsock
WSADATA wsa;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsa))
return 1;
// create socket
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (INVALID_SOCKET == sock)
err_quit("socket()");
// 다른 네트워크에 보낼 때는 ttl을 변경하여 사용
DWORD ttl = 2;
retval = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl));
if (SOCKET_ERROR == retval)
err_quit("setsockopt(IPPROTO_IP, IP_MULTICAST_TTL)");
// connect()
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
inet_pton(AF_INET, MULTICASTIP, &serveraddr.sin_addr);
serveraddr.sin_port = htons(SERVERPORT);
// variables declaration
char buf[BUFSIZE + 1] = { 0, };
int len = 0;
// data communication
while (1)
{
// get data to send
printf("\n[data to send] ");
if (fgets(buf, BUFSIZE + 1, stdin) == NULL)
break;
// remove null terminate character
len = (int)strlen(buf);
if ('\n' == buf[len - 1])
buf[len - 1] = '\0';
// no data to send
if (0 == strlen(buf))
break;
// send data
retval = sendto(sock, buf, (int)strlen(buf), 0, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (SOCKET_ERROR == retval)
{
err_display("sendto()");
break;
}
printf("[UDP client] %d bytes sent.\n", retval);
}
// close socket
closesocket(sock);
// close socket
WSACleanup();
return 0;
}
IPPROTO_IP, IPPROTO_IPV6 레벨 옵션
IP_MULTICAST_IF, IPV6_MULTICAST_IF
용도
IP 주소를 두 개 이상 보유한 호스트에서 멀티캐스트 데이터를 보낼 네트워크 인터페이스를 선택
IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS
TTL = Time-to-live
- 데이터그램이 통과할 수 있는 라우터 갯수 (Hops)
- 데이터그램이 인터넷 시스템에 남아 있도록 허용되는 최대시간
- 라우터를 지날 때마다 TTL을 1씩 감소시키고, 0이 되면 해당 라우터에서 데이터그램을 폐기
- 라우팅 프로토콜의 잘못된 동작으로 인하여 데이터그램이 목적지로 가지 못하고 순환하고, 계속 전송될 수 있음 = 추가 트래픽 (혼잡) 초래
- TTL은 발신지에서 지정함
- IANA에서 TTL 기본값을 64로 제안하나, 필요시 다른 값도 사용 가능
용도
IP 헤더의 TTL(또는 Hop Limit) 값을 변경
- 멀티캐스트 패킷이 생성될 때 IP 헤더의 TTL 필드는 기본값 1로 설정됨
- TTL은 라우터를 통과할 때마다 1씩 감소하는데, 0이 되면 패킷이 버려짐
- TTL = 1 은 패킷이 라우터 경계를 넘어갈 수 없다는 것을 뜻함
- 라우터의 경계를 넘어 특정 범위까지 멀티캐스트 패킷을 보내려면 TTL 값을 변경해야 함 = 다른 네트워크에 보낼 때
- IPv4 일 때 IP_MULTICAST_TTL / IPv6 일 때 IPV6_MULTICAST_HOPS
사용 예
IP datagram
IP(V6)_MULTICAST_LOOP
용도
멀티캐스트 그룹에 가입한 응용 프로그램이 자신의 그룹에 멀티캐스트 데이터를 보낼 때, 자신도 받을지를 결정
사용 예
자신도 받을 거면 = 0이 아닌 값
자신도 받지 않을 거면 = 0
IP_ADD_MEMBERSHIP / IP_DROP_MEMBERSHIP
IPv6에서는 IPV6_JOIN_GROUP / IPV6_LEAVE_GROUP
용도
멀티캐스트 그룹에 가입 또는 탈퇴
사용 예 - IPv4
사용 예 - IPv6
옵션 값
(아래에 mreq 구조체에 자세히 설명)
- 가입하거나 탈퇴할 IPv4 / IPv6 주소
- 멀티캐스트 패킷을 받을 IPv4 주소 = INADDR_ANY 로 자동으로 선택하는 것이 일반적
- 멀티캐스트 패킷을 받을 네트워크 인터페이스 인덱스 = 0을 전달하여 자동으로 선택하는 것이 일반적
ip_mreq / ipv6_mreq 구조체
typedef struct ip_mreq {
IN_ADDR imr_multiaddr;
IN_ADDR imr_interface;
} IP_MREQ, *PIP_MREQ;
imr_multiaddr
IPv4의 멀티캐스트 그룹의 주소
imr_interface
멀티캐스트 패킷을 받을 IPv4 주소 = INADDR_ANY를 보통 사용
typedef struct ipv6_mreq {
IN6_ADDR ipv6mr_multiaddr;
ULONG ipv6mr_interface;
} IPV6_MREQ, *PIPV6_MREQ;
ipv6mr_multiaddr
IPv6의 멀티캐스트 그룹의 주소
멀티캐스트 패킷을 받을 네트워크 인터페이스 = 0 을 보통 사용
ip_mreq 사용 예
728x90
반응형
LIST
'코딩 > Network' 카테고리의 다른 글
[네트워크] IPPROTO_TCP 레벨 옵션 (0) | 2023.06.06 |
---|---|
[네트워크] 소켓 옵션 / SOL_SOCKET 옵션 (1) | 2023.06.06 |
[네트워크] 브로드캐스팅 (0) | 2023.06.06 |
[네트워크] UDP 서버-클라이언트 (0) | 2023.06.05 |
[네트워크] 멀티스레드 TCP서버/스레드 동기화/임계영역/이벤트 (0) | 2023.06.05 |