组播
了解如下三点:
- 只有同在一个组播ip下的各个程序才能接收组播的UDP报文。
- 组播必须使用IP为D类地址,即
224.0.0.1-239.255.255.255
范围地址。 - 组播通过装包将应用数据传入UDP包,再将UDP包放入IP包中,最后将IP中目标地址(即组播地址)的低23位复制到目标MAC地址的低23位,这样在MAC层上接收方就可以检测是否自己是否应该接受同组的地址,接收方IP层同样也会再次判断是否为同组报文,传输层UDP对应端口接收数据。
代码跟学
至于UDP协议、IP协议、MAC协议,这里就不做介绍了,就是一个规范的内容。接下来我们写两个程序,一个接收,一个发送。
接收程序内,需要将socket属性中设置组播地址和自己ip,这样才能接收该组播信息到ip层,udp层是针对端口相同的才能接收。
发送程序,则需要在发送时,向组播地址和端口发送数据。
发送程序代码示例:
void print_exit(char* con)
{
printf("%s",con);
exit(EXIT_FAILURE);
}
int main(int argc, char**argv)
{
struct sockaddr_in peeraddr, myaddr;
int sockfd;
char recmsg[BUFLEN + 1];
unsigned int socklen;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0){
print_exit("socket createing error");
}
//设置组播地址和端口
socklen = sizeof(struct sockaddr_in);
memset(&peeraddr, 0, socklen);
peeraddr.sin_family = AF_INET;
peeraddr.sin_port = htons(7838);
if (argv[1]){
if(inet_pton(AF_INET, argv[1], &peeraddr.sin_addr) <= 0){
print_exit("wrong group address!\n");
}
}
else {
print_exit("no group address\n");
}
//设置本地地址和端口
memset(&myaddr, 0, socklen);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(8888);
if( argv[2] )
{
if(inet_pton(AF_INET, argv[2], &myaddr.sin_addr) <= 0)
{
print_exit("self ip address error!\n");
}
else
{
myaddr.sin_addr.s_addr = INADDR_ANY;
}
}
else{
print_exit("self ip address null!\n");
}
//绑定本地地址和端口到socket上
if(bind(sockfd, (struct sockaddr*) &myaddr, sizeof(struct sockaddr_in)) == -1)
{
print_exit("bind ip error!\n");
}
for(;;){
bzero(recmsg, BUFLEN + 1);
printf("pls enter message to send:");
if(fgets(recmsg, BUFLEN, stdin) == (char*) EOF)
print_exit("enter nothing exit");
//发送数据到peeraddr所代表的目标地址和端口
if(sendto(sockfd, recmsg, strlen(recmsg), 0, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) < 0)
{
print_exit("sendto error!\n");
}
printf("you have send message:%s [ local ip:%s ----> group ip:%s ]\n", recmsg,argv[1], argv[2]);
}
}
运行测试:
仅仅运行发送端代码,在linux环境下运行的,使用如下命令先编译,再运行。
gcc udp_g_brodcast_send.c -o udp_g_brodcast_send
./udp_g_brdcast_send 225.1.1.1 192.168.1.8
结果如下图显示。
小结
今天先学习组播的发送端,明天写接收端以及完整示例演示。