UDP组播通信
组播IP地址: D类IP地址 1110.********** 224.0.0.1 ~ 239.255.255.255
组播MAC地址:低23位,直接对应IP地址, 从右数第24位为0, 前24位为 01:00:5E
最终数据帧如图
局域网所有主机网卡都会收到这一消息,但是只有加入到组内的主机才接受该数据包。组播不影响同一局域网内其他主机的效率。
将自己的主机IP地址加入到组播地址组:
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq));
第四个参数的类型如下:
struct ip_mreqn { struct in_addr imr_multiaddr; //组播地址 struct in_addr imr_address; //自己IP地址 };
加入相应的组后,即可接收对应组播地址的数据包了
例子:
发送端:发送组播消息 绑定了自己的ip 没有加入组 只是说发送到某个组
接收端:加入了正确的组,则可以接收到;没有加入相应的组,则不能接收到
用到了新的函数
gethostbyname
#include<netdb.h> struct hostent* gethostbyname(const char* hostname);
返回值类型
struct hostent{ char * h_name; char ** h_aliases; short h_addrtype; short h_length; char ** h_addr_list; }; #define h_addr h_addr_list[0]
bcopy
void bcopy(const void *src, void *dest, int n);
发送端代码:
#include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #define BUFLEN 255 int main(int argc, char **argv) { struct sockaddr_in peeraddr, myaddr; int sockfd; char recmsg[BUFLEN + 1]; unsigned int socklen; //以UDP方式创建SOCKET对象 sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { printf("socket creating error "); exit(EXIT_FAILURE); } socklen = sizeof(struct sockaddr_in); memset(&peeraddr, 0, socklen); peeraddr.sin_family = AF_INET; peeraddr.sin_port = htons(7838); if(argv[1]) //参数1 获取组播地址 { if(inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) { printf("wrong group address! "); exit(EXIT_FAILURE); } } else { printf("no group address! "); exit(EXIT_FAILURE); } memset(&myaddr, 0, socklen); myaddr.sin_family = AF_INET; myaddr.sin_port = htons(23456); if(argv[2]) //参数2 读取本机绑定的IP地址 { if(inet_pton(AF_INET, argv[2], &myaddr.sin_addr) <= 0) { printf("self ip address error! "); exit(EXIT_FAILURE); } } else { myaddr.sin_addr.s_addr = INADDR_ANY; } //绑定 if(bind(sockfd, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_in)) == -1) { printf("Bind error "); exit(EXIT_FAILURE); } while(1) { bzero(recmsg, BUFLEN + 1); printf("input message to send:"); if(fgets(recmsg, BUFLEN, stdin) == (char *)EOF) exit(EXIT_FAILURE); //发送给组播组内主机 if(sendto(sockfd, recmsg, strlen(recmsg), 0, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) < 0) { printf("sendto error "); exit(EXIT_FAILURE); } printf("send message:%s ", recmsg); } }
接收端代码
#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<netinet/in.h> #include<netinet/tcp.h> #include<sys/socket.h> #include<sys/wait.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/time.h> #include<netdb.h> #define BUFLEN 255 int main(int argc, char **argv) { struct sockaddr_in peeraddr; struct in_addr ia; int sockfd; char recmsg[BUFLEN + 1]; unsigned int socklen, n; struct hostent *group; struct ip_mreq mreq; //创建socket UDP sockfd = socket(AF_INET, SOCK_DGRAM, 0); //创建UDP方式的socket if(sockfd < 0) { perror("socket"); exit(EXIT_FAILURE); } bzero(&mreq, sizeof(struct ip_mreq)); //从参数1获取组播地址 if(argv[1]) { if((group = gethostbyname(argv[1])) == (struct hostent *)0) //?? { perror("gethostbyname"); exit(EXIT_FAILURE); } } else { printf("please input a group address: 224.0.0.1 ~ 239.255.255.255 "); exit(EXIT_FAILURE); } bcopy((void *)group->h_addr, (void *)&ia, group->h_length); //?? bcopy(&ia, &mreq.imr_multiaddr.s_addr, sizeof(struct in_addr)); //?? //从参数2中读取本机IP地址 if(argv[2]) { if(inet_pton(AF_INET, argv[2], &mreq.imr_interface.s_addr) <= 0) { printf("Wrong dest IP address! "); exit(EXIT_FAILURE); } } else { printf("Wrong dest IP address! "); exit(EXIT_FAILURE); } //设置客户端加入到组 if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1) { perror("setsockopt"); exit(EXIT_FAILURE); } // socklen = sizeof(struct sockaddr_in); memset(&peeraddr, 0, socklen); peeraddr.sin_family = AF_INET; peeraddr.sin_port = htons(7838); if(argv[1]) //参数1 获取组播地址 { if(inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0) { printf("wrong group address! "); exit(EXIT_FAILURE); } } else { printf("no group address! "); exit(EXIT_FAILURE); } //绑定 if(bind(sockfd, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) == -1) { printf("Bind error "); exit(EXIT_FAILURE); } while(1) { bzero(recmsg, BUFLEN + 1); n = recvfrom(sockfd, recmsg, BUFLEN, 0, (struct sockaddr *)&peeraddr, &socklen); if(n < 0) { printf("recvfrom err in udptalk! "); exit(EXIT_FAILURE); } else { recmsg[n] = 0; printf("peer:%s ", recmsg); } } }