组播包的发送和接收依然是通过UDP套接字来实现。组播包发送的流程如下所示。
(1)创建UDP套接字。
(2)指定目标地址和端口。
(3)发送数据包。
1 #include <stdio.h>
2 #include <arpa/inet.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <netinet/in.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9
10 #define N 128
11 #define errlog(errmsg) do{perror(errmsg);\
12 printf("%s--%s--%d\n",\
13 __FILE__, __func__, __LINE__);\
14 exit(1);\
15 }while(0)
16
17 int main(int argc, const char *argv[])
18 {
19 int sockfd;
20 struct sockaddr_in groupcastaddr;
21 socklen_t addrlen = sizeof(groupcastaddr);
22 char buf[N] = {};
23
24 if(argc < 3)
25 {
26 fprintf(stderr, "Usage: %s ip port\n", argv[0]);
27 exit(1);
28 }
29
30 //第一步:创建套接字
31 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
32 {
33 errlog("fail to socket");
34 }
35
36 //第二步:填充组播网络信息结构体
37 //inet_addr:将点分十进制ip地址转化为网络字节序的整型数据
38 //htons:将主机字节序转化为网络字节序
39 //atoi:将数字型字符串转化为整型数据
40 groupcastaddr.sin_family = AF_INET;
41 //224.x.x.x - 239.x.x.x
42 groupcastaddr.sin_addr.s_addr = inet_addr(argv[1]);
43 groupcastaddr.sin_port = htons(atoi(argv[2]));
44
45 while(1)
46 {
47 fgets(buf, N, stdin);
48 buf[strlen(buf) - 1] = '\0';
49
50 if(sendto(sockfd, buf, N, 0,\
51 (struct sockaddr *)&groupcastaddr, addrlen) < 0)
52 {
53 errlog("fail to sendto");
54 }
55
56 }
57
58 close(sockfd);
59
60 return 0;
61 }
在IPv4英特网域(AF_INET)中,组播地址结构体用如下结构体ip_mreq表示。
typedef uint32_t in_addr_t;
struct in_addr{
in_addr_t s_addr;
};
struct ip_mreq {
struct in_addr imr_multiaddr; /*组播的IP地址*/
struct in_addr imr_interface; /*本机的IP地址*/
};
组播包接收流程如下。
(1)创建UDP套接字。
(2)绑定地址和端口。
(3)加入多播组。
(4)接收数据包。
1 #include <stdio.h>
2 #include <arpa/inet.h>
3 #include <sys/types.h>
4 #include <sys/socket.h>
5 #include <netinet/in.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9
10 #define N 128
11 #define errlog(errmsg) do{perror(errmsg);\
12 printf("%s--%s--%d\n",\
13 __FILE__, __func__, __LINE__);\
14 exit(1);\
15 }while(0)
16
17 int main(int argc, const char *argv[])
18 {
19 int sockfd;
20 struct sockaddr_in groupcastaddr, addr;
21 socklen_t addrlen = sizeof(groupcastaddr);
22 char buf[N] = {};
23
24 if(argc < 3)
25 {
26 fprintf(stderr, "Usage: %s ip port\n", argv[0]);
27 exit(1);
28 }
29
30 //第一步:创建套接字
31 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
32 {
33 errlog("fail to socket");
34 }
35
36 //第二步:填充组播网络信息结构体
37 //inet_addr:将点分十进制ip地址转化为网络字节序的整型数据
38 //htons:将主机字节序转化为网络字节序
39 //atoi:将数字型字符串转化为整型数据
40 groupcastaddr.sin_family = AF_INET;
41 groupcastaddr.sin_addr.s_addr = inet_addr(argv[1]); //224-239
42 groupcastaddr.sin_port = htons(atoi(argv[2]));
43
44 //第三步:将套接字与服务器网络信息结构体绑定
45 if(bind(sockfd, (struct sockaddr *)&groupcastaddr, addrlen) < 0)
46 {
47 errlog("fail to bind");
48 }
49
50 //加入多播组,允许数据链路层处理指定数据包
51 struct ip_mreq mreq;
52 mreq.imr_multiaddr.s_addr = inet_addr(argv[1]);
53 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
54
55 if(setsockopt(sockfd, IPPROTO_IP,\
56 IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
57 {
58 errlog("fail to setsockopt");
59 }
60
61 ssize_t bytes;
62 while(1)
63 {
64 if((bytes = recvfrom(sockfd, buf, N, 0,\
65 (struct sockaddr *)&addr, &addrlen)) < 0)
66 {
67 errlog("fail to recvfrom");
68 }
69 else
70 {
71 printf("ip: %s, port: %d\n",\
72 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
73
74 printf("groupcast : %s\n", buf);
75
76 }
77 }
78
79 close(sockfd);
80
81 return 0;
82 }
版权声明:本文为anton_99原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。