코딩/Network

[네트워크] 멀티캐스트, IPPROTO_IP, IPPROTO_IPV6 레벨 옵션

나야, 웅이 2023. 6. 6. 18:57
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

사용 예

 

IPv4
IPv6

 

 

IP datagram

 

IP(V6)_MULTICAST_LOOP

용도

멀티캐스트 그룹에 가입한 응용 프로그램이 자신의 그룹에 멀티캐스트 데이터를 보낼 때, 자신도 받을지를 결정

 

사용 예

자신도 받을 거면 =  0이 아닌 값

자신도 받지 않을 거면 =  0

 

IP_ADD_MEMBERSHIP / IP_DROP_MEMBERSHIP

IPv6에서는 IPV6_JOIN_GROUP / IPV6_LEAVE_GROUP

 

용도

멀티캐스트 그룹에 가입 또는 탈퇴

 

사용 예 - IPv4

 

사용 예 - IPv6

 

옵션 값

(아래에 mreq 구조체에 자세히 설명)

  1. 가입하거나 탈퇴할 IPv4 / IPv6 주소
  2. 멀티캐스트 패킷을 받을 IPv4 주소 = INADDR_ANY 로 자동으로 선택하는 것이 일반적
  3. 멀티캐스트 패킷을 받을 네트워크 인터페이스 인덱스 = 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