单播方式只能发给一个接收方
广播方式发给所有的主机。过度的广播会大量占用网络带宽,造成广播风暴,影响正常通信。
组播(又称为多播)是一种折中的方式。只有加入某个多跛足的主机才能收到数据。
多播方式既可以发给多个主机,又能避免像广播那样带来过多的负荷(每台主机要到传输层才能判断广播包是否要处理)
网络地址:
A类地址:
第1个字节为网络地址,其他3个字节为主机地址
第一个字节的最高位固定为0
地址范围 1.0.0.1 - 126.255.255.255
B类地址:
第一个和第二个字节为网络地址,其他2个字节为主机地址,第一个字节的前两位固定为10
地址范围:128.0.0.1 - 191.255.255.255
C类地址:
前3个字节为网络地址,最后1个字节是主机地址。第一字节的前3位固定为110
地址范围:192.0.0.1 - 223.255.255.255
D类地址:(组播地址)
不分网络地址和主机地址,第一个字节的前4位固定为1110
地址范围: 224.0.0.1 - 239.255.255.255
224.0.0.1 - 224.0.0.255是被保留的地址,组播的时候不要占用。
组播的发送;
创建数据报套接字
接收方地址指定为组播地址
指定端口信息
发送数据包
例如:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
int main(int argc, char **argv)
{
int sockfd, clientfd;
struct sockaddr_in servaddr, clientaddr;
char buf[1024];
socklen_t len;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
printf("socket = %d\n", sockfd);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8888);
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
len = sizeof(clientaddr);
while(1)
{
fgets(buf, sizeof(buf), stdin);
sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, len);
}
}
组播的接受
创建套接字
加入多播组
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq));
绑定
等待接收
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <bits/time.h>
#define BUFSIZE 1024
int main()
{
int sockfd, clientfd;
struct sockaddr_in servaddr, clientaddr;
char buf[1024];
socklen_t len;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq));
printf("socket = %d\n", sockfd);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8888);
//servaddr.sin_addr.s_addr = inet_addr("192.168.1.241");
servaddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
exit(1);
}
while(1)
{
len = sizeof(clientaddr);
recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&clientaddr, &len);
printf("ip = %s, port = %d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
printf("buf = %s\n", buf);
}
return 0;
}