OSI 7 Layer
이름 | 역할 | 예제 |
---|---|---|
Application | End user Layer | HTTP, HTP, IRC |
Presentaion | Syntax Layer | SSL, SSH, IMAP, FTP |
Session | Synch & send to PORT | API's Sockets |
Transport | End-to-End Connection | TCP, UDP |
Network | Packets | IP, ICMP, IPSec |
Data Link | Frames | Ethernet, Switch, Bridge |
Physical | Physical structure | Coax, Fiber, Wireless |
<br>
TCP/IP
이름 | 역할 | 예제 |
---|---|---|
Application | To allow access to network resources | HTTP, FTP, DNS |
Transport | to provide reliable process to process message delivery and error delevery | TCP, UDP |
Internet | To move Packet src to dest | ARP, ICMP |
Network Interface | Transmission for two device on the same network | Ethernet, ATM ... |
1. 결론
1. 네트워크 작업의 데이터 흐름을 추상화 및 계층화해서 보면 좋은 이유
- 문제가 일어나면 다른 계층에는 관여하지 않고 해당 문제가 일어나는 특정한 계층만 고칠 수 있다.
- 예를 들어 상하 구조를 가지고 있기 때문에 1-4단계까지 완벽하고 5단계만 문제가 있다면 5단계만 이슈가 나는 부분을 보면 된다.
- 통신이 일어나는 과정을 단계별로 파악할 수 있다.
계층 | ADDRESS | 예제 |
---|---|---|
Datalink | Mac Address | E0-15-4D-90-7A-DA |
Network | IP Address | 172.168.42.3 |
Transport | Port Number | 22 |
User DatagramProtocol
비 연결성
오류 검사를 거의 수행하지 않는다.(check sum 정도만 함)
프로세스 간 통신을 제공 이외에 IP 서비스에는 아무것도 추가하지 않는다.
최소한의 오버헤드
소규모 메시지, 신뢰성이 중요하지 않은 경우(속도가 중요한 서비스)에 주로 사용
멀티캐스팅 애플리케이션에 편함
헤더
전송 제어 프로토콜 (TransMission Control Protocol)
IP에 연결 지향 기능 및 신뢰성을 추가
신뢰할 수 있는 스트림 전달 서비스
손실이나 중복없이 데이터 전송 보장
클라이언트(대화를 시작할 프로세스)와 서버(피어가 시작될 때까지 기다리는)가 지정되어야 함
통신 과정
헤더 구조
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 128
void error_handling(char *message);
int main(int argc, char*argv[]){
//소켓 디스크립터
int serv_sock;
//보낼 메시지를 담는 배열형태의 변수
char message[BUF_SIZE];
//클라이언트로 부터 수신 받은 문자열 길이
int str_len;
socklen_t clnt_adr_sz;
struct sockaddr_in serv_adr, clnt_adr;
//실행파일 경로 /port 번호 입력받기
if (argc != 2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
//udp 소켓 생성
serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (serv_sock == -1) {
error_handling("udp socket creation error");
}
//서버 주소 정보 초기화
memset(&serv_adr , 0 , sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
//서버 주소 정보 할당
if (bind(serv_sock , (struct sockaddr *)&serv_adr , sizeof(serv_adr)) == -1) {
error_handling("bind creation error");
}
//
while (1) {
clnt_adr_sz = sizeof(clnt_adr);
//클라이언트로부터 널 문자를 제외하고 문자열 수신
str_len = recvfrom(serv_sock, message , BUF_SIZE, 0,
(struct sockaddr*)&clnt_adr , &clnt_adr_sz);
// write 를 이용해 받은 만큼 출력
write(1, message, str_len);
}
//udp 소켓 종료
close(serv_sock);
return 0;
}
//에러처리
void error_handling(char *message){
fputs(message , stderr);
fputc('\n' , stderr);
exit(1);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 128
void error_handling(char *message);
int main (int argc, char *argv[]){
//소켓 디스크립터
int sock;
//보낼 메시지를 담는 배열형태의 변수
char message[BUF_SIZE];
//서버로 부터 받은 메시지 길이
int str_len;
socklen_t adr_sz;
//주소 구조체
struct sockaddr_in serv_adr, from_adr;
//인자로 연결할 ip 주소 / port 번호
if(argc!=3){
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
//UDP 소켓 생성
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
error_handling("socket() error");
}
//서버주소 정보 초기화
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
serv_adr.sin_port=htons(atoi(argv[2]));
while (1) {
fputs("insert message(q to quit) :",stdout);
fgets(message , sizeof(message), stdin);
if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")) {
break;
}
/*
클라이언트의 주소가 자동으로 할당됨
입력받은 문자열을 서버로 널문자를 제외하고 송신
데이터를 전송할 때마다 반드시 목적지의 주소 정보를 별도로 추가해야한다.
(tcp 처럼 연결된 상태가 아니기 때문에.)
*/
sendto(sock, message, strlen(message) , 0 ,
(struct sockaddr*)&serv_adr , sizeof(serv_adr));
}
//udp 소켓 종료
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#define MAXBUF 256
#define EQ ==
int main()
{
int ssock, csock; // 소켓 스크립트 정의
int clen;
struct sockaddr_in client_addr, server_addr; // 주소 구조체
char buf[MAXBUF] = "Message from Server"; // 클라이언트에 보내줄 문자
// 서버 소켓 생성
if ((ssock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
perror("socket error :");
exit(1);
}
clen = sizeof(client_addr);
// 주소 구조체에 주소 지정
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(1000);
// 사용할 포트로 1000번 포트 사용
//bind() 사용해서 서버소켓의 주소 설정
if (bind(ssock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
perror("bind error: ");
exit(1);
}
//위에서 지정한 주소로 크라이언트 접속을 기다림
if (listen(ssock, 8) < 0)
{
perror("listen error : ");
exit(1);
}
while (1)
{
// 클라이언트가 접속하면 접속을 허용하고 , 클라이언트 소켓을 생성
csock = accept(ssock, (struct sockaddr *)&client_addr, &clen);
//클라이언트로 buf에 있는 문자열 발송
if (write(csock, buf, MAXBUF) <= 0)
perror("write error: ");
// 클라이언트 소켓을 닫음
close(csock);
}
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#define MAXBUF 256
#define EQ ==
int main()
{
int ssock;
int clen;
//소켓 생성
struct sockaddr_in server_addr;
char buf[MAXBUF];
if((ssock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) <0){
perror("socket error : ");
exit(1);
}
clen = sizeof(server_addr);
//소켓에 접속할 주소 지정
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(1000);
// 지정한 주소로 접속
if(connect(ssock, (struct sockaddr *)&server_addr, clen)<0){
perror("connect error : ");
exit(1);
}
memset(buf, 0, MAXBUF);
//서버에서 전송하는 문자열을 받음
if(read(ssock, buf, MAXBUF) <= 0){
perror("read error : ");
exit(1);
}
// 소켓 닫음
close(ssock);
// 받아온 문자열 출력
printf("\nread : %s\n\n", buf);
return 0;
}
#include <sys/types.h>
#include <sys/socket.h>
int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
//에러처리
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
//시그널 핸들러
void read_childproc(int sig){
pid_t pid;
int status;
//임의의 자식 프로세스가 종료되길 기다림
pid = waitpid(-1, &status , WNOHANG);
//자식 프로세스가 정상 종료될때 true 반환
if (WIFEXITED(status)) {
printf("removed proc id : %d \n" , pid); //종료된 자식프로세스
printf("removed proc send : %d \n" , WEXITSTATUS(status)); //전달된 값
}
}
int main(int argc, char *argv[])
{
//서버, 클라이언트 소켓
int serv_sock, clnt_sock;
//소켓에 할당할 주소 정보 구조체
struct sockaddr_in serv_adr, clnt_adr;
//프로세스 id
pid_t pid;
//시그널 정보 구조체
struct sigaction act;
//클라이언트 소켓 길이
socklen_t adr_sz;
int str_len , state;
//전달할 데이터를 담을 char 배열
char buf[BUF_SIZE];
//실행파일의 경로 + port 를 인자로 받는다.
if (argc != 2) {
printf("usage : %s <port> \n" , argv[0]);
exit(1);
}
//sigaction 구조체 초기화
act.sa_handler = read_childproc; //시그널 핸들러는 read_childproc 함수포인터
sigemptyset(&act.sa_mask); //0으로 초기화
act.sa_flags = 0 ; //0으로 초기화
//자식 프로세스 종료시 read_childproc 함수 호출되게 운영체제에게 등록
state = sigaction(SIGCHLD,&act,0); //운영체제에 시그널 등록
//IPv4, TCP 소켓 생성
serv_sock = socket(PF_INET,SOCK_STREAM,0);
//서버주소 정보 초기화
memset(&serv_adr , 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
//서버 주소정보를 기반으로 주소 할당
if (bind(serv_sock, (struct sockaddr*)&serv_adr , sizeof(serv_adr)) == -1) {
error_handling("bind() error...");
}
//서버가 클라이언트의 연결 요청 준비를 완료
if (listen(serv_sock , 5) == -1) {
error_handling("listen() error...");
}
// <-------------------- 서버 준비 완료 --------------------------->
while (true) {
adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock , (struct sockaddr*)&clnt_adr , &adr_sz);
if (clnt_sock == -1) {
continue;
}else{
puts("new client connected...");
//자식 프로세스 생성
pid = fork();
//프로세서 생성 오류 처리
if (pid == -1) {
continue;
}
//자식프로세스 인경우
if (pid == 0) {
close(serv_sock); //자식 프로세스는 서버소켓 파일 디스크립터 필요없음.
while (1) {
//클라이언트 에서 보낸 데이터 읽어서
str_len = read(clnt_sock, buf, BUF_SIZE);
if (str_len == 0) {
printf("str_len == 0 \n" );
break;
}
//클라이언트에 다시 에코..(전달..)
write(clnt_sock , buf, str_len);
}
//클라이언트에 대한 에코 서비스를 모두 완료 했으므로 소켓 연결 종료
close(clnt_sock);
puts("client disconnected...");
//자식 프로세스 종료
return 0;
}else{
//부모 프로세스 경우 클라이언트 소켓은 필요없다. - 자식만 필요
close(clnt_sock);
}
}
}
//부모 프로세스에서 서버 소켓 종료
close(serv_sock);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[])
{
int sock;
char message[BUF_SIZE];
int str_len;
struct sockaddr_in serv_adr;
if(argc!=3) {
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
sock=socket(PF_INET, SOCK_STREAM, 0);
if(sock==-1)
error_handling("socket() error");
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
serv_adr.sin_port=htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
error_handling("connect() error!");
else
puts("Connected...........");
while(1)
{
fputs("Input message(Q to quit): ", stdout);
fgets(message, BUF_SIZE, stdin);
if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
break;
write(sock, message, strlen(message));
str_len=read(sock, message, BUF_SIZE-1);
message[str_len]=0;
printf("Message from server: %s", message);
}
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
멀티 프로세스 기반의 서버는 아래와 같은 단점을 가지고 있다.
쓰레드의 사용
멀티쓰레드의 메모리 구조와 멀티프로세스의 메모리 구조
멀티프로세스
멀티 쓰레드
쓰레드의 생성과 실행 흐름 구성
쓰레드는 쓰레드만의 main 함수를 별도로 정의해야 한다.
그리고 이함수를 시작으로 별도의 실행 흐름을 형성해 줄것을 OS 에세 요청해야 하는데
쓰레드의 실행 형태를 그림으로 표현하면 아래와 같다.
쓰레드는 메인 함수가 종료하여 프로세스가 전체 소멸되어 버리면 쓰레드도 함께 종료된다.
이럴 땐 thread_join 함수를 이용하여 쓰레드의 종료를 대기해준다.
#include <pthread.h>
// 뮤택스 생성시
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
// 뮤택스 소멸시
int pthread_mutex_destroy(pthread_mutex_t *mutex)
// 임계영역 잠그기, 풀기
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex); // 성공 시 0, 실패 시 0 이외의 값 반환
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#define BUF_SIZE 100
#define MAX_CLNT 256
void * handle_clnt(void * arg);
void send_msg(char * msg, int len);
void error_handling(char * msg);
int clnt_cnt=0; // 서버에 접속한 클라이언트의 소켓 관리를 위한 변수와 배열
int clnt_socks[MAX_CLNT]; // 이 둘은 접근과 관련있는 코드가 임계영역을 구성하게 됨에 주목하자.
pthread_mutex_t mutx;
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
int clnt_adr_sz;
pthread_t t_id;
if(argc!=2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
pthread_mutex_init(&mutx, NULL);
serv_sock=socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)
error_handling("bind() error");
if(listen(serv_sock, 5)==-1)
error_handling("listen() error");
while(1)
{
clnt_adr_sz=sizeof(clnt_adr);
clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr,&clnt_adr_sz);
pthread_mutex_lock(&mutx);
clnt_socks[clnt_cnt++]=clnt_sock;
pthread_mutex_unlock(&mutx);
pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);
pthread_detach(t_id);
printf("Connected client IP: %s \n", inet_ntoa(clnt_adr.sin_addr));
}
close(serv_sock);
return 0;
}
void * handle_clnt(void * arg)
{
int clnt_sock=*((int*)arg);
int str_len=0, i;
char msg[BUF_SIZE];
while((str_len=read(clnt_sock, msg, sizeof(msg)))!=0)
send_msg(msg, str_len);
pthread_mutex_lock(&mutx);
for(i=0; i<clnt_cnt; i++) // remove disconnected client
{
if(clnt_sock==clnt_socks[i])
{
while(i++<clnt_cnt-1)
clnt_socks[i]=clnt_socks[i+1];
break;
}
}
clnt_cnt--;
pthread_mutex_unlock(&mutx);
close(clnt_sock);
return NULL;
}
void send_msg(char * msg, int len) // send to all
{
int i;
pthread_mutex_lock(&mutx);
for(i=0; i<clnt_cnt; i++)
write(clnt_socks[i], msg, len);
pthread_mutex_unlock(&mutx);
}
void error_handling(char * msg)
{
fputs(msg, stderr);
fputc('\n', stderr);
exit(1);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#define BUF_SIZE 100
#define NAME_SIZE 20
void * send_msg(void * arg);
void * recv_msg(void * arg);
void error_handling(char * msg);
char name[NAME_SIZE]="[DEFAULT]";
char msg[BUF_SIZE];
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in serv_addr;
pthread_t snd_thread, rcv_thread;
void * thread_return;
if(argc!=4) {
printf("Usage : %s <IP> <port> <name>\n", argv[0]);
exit(1);
}
sprintf(name, "[%s]", argv[3]);
sock=socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
serv_addr.sin_port=htons(atoi(argv[2]));
if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)
error_handling("connect() error");
pthread_create(&snd_thread, NULL, send_msg, (void*)&sock);
pthread_create(&rcv_thread, NULL, recv_msg, (void*)&sock);
pthread_join(snd_thread, &thread_return);
pthread_join(rcv_thread, &thread_return);
close(sock);
return 0;
}
void * send_msg(void * arg) // send thread main
{
int sock=*((int*)arg);
char name_msg[NAME_SIZE+BUF_SIZE];
while(1)
{
fgets(msg, BUF_SIZE, stdin);
if(!strcmp(msg,"q\n")||!strcmp(msg,"Q\n"))
{
close(sock);
exit(0);
}
sprintf(name_msg,"%s %s", name, msg);
write(sock, name_msg, strlen(name_msg));
}
return NULL;
}
void * recv_msg(void * arg) // read thread main
{
int sock=*((int*)arg);
char name_msg[NAME_SIZE+BUF_SIZE];
int str_len;
while(1)
{
str_len=read(sock, name_msg, NAME_SIZE+BUF_SIZE-1);
if(str_len==-1)
return (void*)-1;
name_msg[str_len]=0;
fputs(name_msg, stdout);
}
return NULL;
}
void error_handling(char *msg)
{
fputs(msg, stderr);
fputc('\n', stderr);
exit(1);
}
#include <sys/select.h>
#include <sys/time.h>
int select( int maxfd, fd_set* readset, fd_set* writeset, fd_set* exceptset, const struct timeval* timeout);
// 성공 : 0 반환
// 실패 : -1 반환
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#define BUFSIZE 100
void errorHandling(char *buf);
int main(int argc, char *argv[])
{
int servSock, clntSock;
struct sockaddr_in servAddr, clntAddr;
struct timeval timeout;
fd_set reads, cpyReads;
socklen_t addrSz;
int fdMax, strLen, fdNum, i;
char buf[BUFSIZE];
if (argc != 2)
{
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
// 소켓 초기화
servSock = socket(PF_INET, SOCK_STREAM, 0);
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(argv[1]));
// 소켓 bind, listen
if (bind(servSock, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)
errorHandling("bind() error");
if (listen(servSock, 5) == -1)
errorHandling("listen() error");
// read 모든 비트 0으로 초기화
FD_ZERO(&reads);
// server socket에 파일디스크립터 정보 등록
FD_SET(servSock, &reads);
fdMax = servSock;
while (1)
{
cpyReads = reads;
// 타임아웃 설정
timeout.tv_sec = 5;
timeout.tv_usec = 5000;
// 오류가 나면 바로 꺼준다.
if ((fdNum = select(fdMax + 1, &cpyReads, 0, 0, &timeout)) == -1)
break;
if (fdNum == 0)
continue;
for (i = 0; i < fdMax + 1; i++)
{
// fdset으로 전달된 주소의 변수에 매개변수 fd 로 전달된 파일디스크립터 정보가 있으면 양수 반환
if (FD_ISSET(i, &cpyReads))
{
// 서버 소켓이라면
if (i == servSock)
{
addrSz = sizeof(clntAddr);
// accept
clntSock = accept(servSock, (struct sockaddr *)&clntAddr, &addrSz);
FD_SET(clntSock, &reads);
if (fdMax < clntSock)
fdMax = clntSock;
printf("connected client : %d\n", clntSock);
}
else
{
strLen = read(i, buf, BUFSIZE);
// close request
if (strLen == 0)
{
FD_CLR(i, &reads);
close(i);
printf("close client : %d\n", i);
}
else
{
// echo
write(i, buf, strLen);
}
}
}
}
}
close(servSock);
return 0;
}
네트워크에 연결되어 있는 시스템 중 일부에게만 정보를 전송하는 것
특정 그룹에 속해있는 시스템에게만 한 번에 정보를 전달하는 방법
특징
멀티캐스트 IP 주소 체계
IP | 설명 |
---|---|
224.0.0.0 ~ 224.0.0.225 | IETF에서 관리용으로 사용되는 영역 |
224.0.1.0 ~ 238.255.255.255 | 실제 인터넷에서 멀티캐스트를 사용하는 기관이나 기업에게 할당하는 내역 |
232.0.0.0 ~ 232.255.255.255 | PIM 기술을 위해 사용하는 대역 |
233.0.0.0 ~ 233.255.255.255 | 하나의 AS 내에 전파를 원할 때 사용하는 대역 |
239.0.0.0 ~ 239.255.255.255 | 기관이나 기업 내부에서 사용할 수 있는 사설 멀티캐스트 주소 |
이 중 주요 IP 두개는 다음과 같은 역할을 한다.
224.0.0.1 : 현재 서브넷에 존재하는 멀티캐스트가 가능한 모든 호스트 지칭
224.0.0.2 : 현재 서브넷에 존재하는 멀티캐스트가 가능한 모든 라우터를 지칭