组播
组播
单播只能发给一个接收方,广播发给所有主机,但过多的广播会大量占用网络带宽,造成网络风暴,影响通信。
组播(多播)为折中方式,只有加入某个多播组的主机才能收到数据。
组播的IP地址:224.0.0.1 ~ 239.255.255.254(中间除去广播地址)
组播的发送
1)创建UDP套接字
2)指定目标地址与端口
3)发送数据包
1 /*udp demo */ 2 3 /* usage: 4 * ./client serv_ip serv_port 5 */ 6 #include "net.h" 7 void usage (char *s) 8 { 9 printf ("\nThis is multicast demo!\n"); 10 printf ("\nUsage:\n\t %s serv_ip serv_port", s); 11 printf ("\n\t serv_ip: udp server ip address(between 224~239 segment)"); 12 printf ("\n\t serv_port: udp server port(serv_port > 5000)\n\n"); 13 } 14 15 int main (int argc, char *argv[]) 16 { 17 int fd = -1; 18 int port = SERV_PORT; 19 20 port = atoi (argv[2]); 21 if (port < 0 || (port > 0 && port <= 5000)) { 22 usage (argv[0]); 23 exit (1); 24 } 25 struct sockaddr_in sin; 26 if (argc != 3) { 27 usage (argv[0]); 28 exit (1); 29 } 30 31 /* 1. 创建socket fd */ 32 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { //UDP缂栫▼ 33 perror ("socket"); 34 exit (1); 35 } 36 37 /*2.1 填充struct sockaddr_in */ 38 bzero (&sin, sizeof (sin)); 39 40 sin.sin_family = AF_INET; 41 sin.sin_port = htons (SERV_PORT); //HBD转为NBD 42 #if 0 43 sin.sin_addr.s_addr = inet_addr (argv[1]); 44 #else 45 if (inet_pton (AF_INET, argv[1], (void *) &sin.sin_addr) != 1) { 46 perror ("inet_pton"); 47 exit (1); 48 } 49 #endif 50 printf ("multicast started!\n"); 51 char buf[BUFSIZ]; 52 while (1) { 53 fprintf (stderr, "pls input string:"); 54 bzero (buf, BUFSIZ); 55 if (fgets (buf, BUFSIZ - 1, stdin) == NULL) { 56 perror ("fgets"); 57 continue; 58 } 59 60 sendto (fd, buf, strlen (buf), 0, (struct sockaddr *) &sin, sizeof (sin)); 61 62 if (!strncasecmp (buf, QUIT_STR, strlen (QUIT_STR))) { 63 printf ("Client is exited!\n"); 64 break; 65 } 66 67 } 68 close (fd); 69 return 0; 70 }
组播的接收
1)创建UDP套接字
2)加入多播组
3)绑定地址与端口
4)接收数据包
1 #include "net.h" 2 3 int main (void) 4 { 5 6 int fd = -1; 7 struct sockaddr_in sin; 8 9 /* 1. 创建socket fd */ 10 if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { //udp 11 perror ("socket"); 12 exit (1); 13 } 14 15 /* 2. 允许地址快速重用 */ 16 int b_reuse = 1; 17 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int)); 18 19 /*加入多播组*/ 20 struct ip_mreq mreq; 21 bzero(&mreq, sizeof(mreq)); //清零 22 mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP); 23 mreq.imr_interface.s_addr = htonl(INADDR_ANY); 24 25 setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)); 26 27 /*2. 绑定*/ 28 /*2.1 填充struct sockaddr_in */ 29 bzero (&sin, sizeof (sin)); 30 sin.sin_family = AF_INET; 31 sin.sin_port = htons (SERV_PORT); 32 /* 使服务器可绑定在任意IP */ 33 #if 1 34 sin.sin_addr.s_addr = htonl (INADDR_ANY); 35 #else 36 if (inet_pton (AF_INET, SERV_IP_ADDR, (void *) &sin.sin_addr) != 1) { 37 perror ("inet_pton"); 38 exit (1); 39 } 40 #endif 41 /*2.2 绑定 */ 42 if (bind (fd, (struct sockaddr *) &sin, sizeof (sin)) < 0) { 43 perror ("bind"); 44 exit (1); 45 } 46 47 char buf[BUFSIZ]; 48 struct sockaddr_in cin; 49 socklen_t addrlen = sizeof (cin); 50 printf ("\nmulticast demo started!\n"); 51 while (1) { 52 bzero (buf, BUFSIZ); 53 if (recvfrom (fd, buf, BUFSIZ - 1, 0, (struct sockaddr *) &cin, &addrlen) < 0) { 54 perror ("recvfrom"); 55 continue; 56 } 57 58 char ipv4_addr[16]; 59 if (!inet_ntop (AF_INET, (void *) &cin.sin_addr, ipv4_addr, sizeof (cin))) { 60 perror ("inet_ntop"); 61 exit (1); 62 } 63 64 printf ("Recived from(%s:%d), data:%s", ipv4_addr, ntohs (cin.sin_port), buf); 65 66 if (!strncasecmp (buf, QUIT_STR, strlen (QUIT_STR))) { / 67 printf ("Client(%s:%d) is exiting!\n", ipv4_addr, ntohs (cin.sin_port)); 68 } 69 70 } 71 72 close (fd); 73 74 return 0; 75 }