文章目录
1,广播
- 前面介绍的数据包发送方式只有一个接受方,称为单播
- 如果同时发给局域网中的所有主机,称为广播
- 只有用户数据报(使用UDP协议)套接字才能广播
- 广播地址
·以192.168.1.0 (255.255.255.0) 网段为例,最大的主机地址192.168.1.255代表该网段的广播地址
·发到该地址的数据包被所有的主机接收
·255.255.255.255在所有网段中都代表广播地址
1.1,广播收发
广播发送 |
广播接受 |
创建用户数据报套接字fd = socket(AF_INET,SOCK_DGRAM,0)
缺省创建的套接字不允许广播数据包,需要设置属性
---setsockopt可以设置套接字属性
接收方地址指定为广播地址
指定端口信息
发送数据包
创建用户数据报套接字
绑定本机IP地址和端口
---绑定的端口必须和发送方指定的端口相同
等待接收数据
1.2,广播收发—示例
1.2.1,net.h
#ifndef __NET_H__
#define __NET_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERV_PORT 5005
#define QUIT_STR "quite"
#endif
1.2.2,sender.c
#include "net.h"
void usage(char *s)
{
printf("this is a boardcast demo!
");
printf("Usage:
%s
",s);
printf(" receiver_ip: boardcast_receiver ip address
");
printf(" receiver_port: boardcast_receiver port(>5000)
");
}
int main(int argc, const char *argv[])
{
int fd;
short port;
struct sockaddr_in sin;
if(argc != 3)
{
usage((char *)argv[0]);
exit(1);
}
if((port = atoi(argv[2])) < 5000)
{
usage((char *)argv[0]);
exit(1);
}
if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
{
perror("socket");
exit(-1);
}
int b_br =1;
setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&b_br,sizeof(int));
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
#if 0
#else
if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
#endif
printf("boardcast sender starting ...... OK!
");
char buf[BUFSIZ];
while(1)
{
fprintf(stderr,"Please input the string to boardcast receiver:");
bzero(buf,BUFSIZ);
if(fgets(buf,BUFSIZ-1,stdin) == NULL)
{
perror("fgets");
continue;
}
sendto(fd,buf,strlen(buf),0,(struct sockaddr *)&sin,sizeof(sin));
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("boardcast sender is existed!
");
break;
}
}
_error1:
close(fd);
return 0;
}
1.2.3,receiver.c
#include "net.h"
int main(int argc, const char *argv[])
{
int fd;
struct sockaddr_in sin;
if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
{
perror("socket");
exit(-1);
}
int b_reuse = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SERV_PORT);
#if 1
sin.sin_addr.s_addr = htonl(INADDR_ANY);
#else
if(inet_pton(AF_INET,SERV_IP_ADDR,(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
#endif
if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)))
{
perror("bind");
goto _error1;
}
printf("boardcast receiver starting .... OK!
");
char buf[BUFSIZ];
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
while(1)
{
bzero(buf,BUFSIZ);
if(recvfrom(fd,buf,BUFSIZ-1,0,(struct sockaddr *)&cin,&addrlen) < 0)
{
perror("recvfrom");
continue ;
}
char cin_ipv4_addr[16];
if(inet_ntop(AF_INET,&cin.sin_addr.s_addr,cin_ipv4_addr,sizeof(cin_ipv4_addr)) < 0)
{
perror("inet_ntop");
goto _error1;
}
printf("Receive broadcast Data: %s",buf);
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("boardcast sender (%s:%d) is existing!
",cin_ipv4_addr,ntohs(cin.sin_port));
}
}
_error1:
close(fd);
return 0;
}
1.2.4,运行结果
接收端
linux@linux:~/test/network/network_broadcast$ ./receiver
boardcast receiver starting .... OK!
Receive broadcast Data: 1
Receive broadcast Data: 2
Receive broadcast Data: 3
Receive broadcast Data: 4
Receive broadcast Data: quite
boardcast sender (192.168.1.100:34256) is existing!
发送端
linux@linux:~/test/network/network_broadcast$ ./sender 192.168.1.255 5005
boardcast sender starting ...... OK!
Please input the string to boardcast receiver:1
Please input the string to boardcast receiver:2
Please input the string to boardcast receiver:3
Please input the string to boardcast receiver:4
Please input the string to boardcast receiver:quite
boardcast sender is existed!
2,组播(多播)
- 单播方式只能发给一个接收方。
- 广播方式发给所有的主机。过多的广播会大量占用网络带宽,造成广播风暴,影响正常的通信。
- 组播(又称为多播)是一种折中的方式。只有加入某个多播组的主机才能收到数据。
- 多播方式既可以发给多个主机,又能避免象广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理)
2.1,网络地址
- A类地址
第1字节为网络地址,其他3个字节为主机地址。第1字节的最高位固定为0
1.0.0.1 – 126.255.255.255
- B类地址
第1字节和第2字节是网络地址,其他2个字节是主机地址。第1字节的前两位固定为10
128.0.0.1 – 191.255.255.255
- C类地址
前3个字节是网络地址,最后1个字节是主机地址。第1字节的前3位固定为110
192.0.0.1 – 223.255.255.255
- D类地址(组播地址)
不分网络地址和主机地址,第1字节的前4位固定为1110
224.0.0.1 – 239.255.255.255
组播地址:224.0.0.1 – 239.255.255.255(中间除掉广播地址)
2.2,组播收发
组播发送 |
组播接受 |
创建用户数据报套接字fd = socket(AF_INET,SOCK_DGRAM,0)
接收方地址指定为组播地址
指定端口信息
发送数据包
创建用户数据报套接字
加入多播组
绑定本机IP地址和端口
---绑定的端口必须和发送方指定的端口相同
等待接收数据
2.2.1,加入多播组
struct ip_mreq
{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr(“235.10.10.3”);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
2.3,组播收发 — 示例
2.3.1,net.h
#ifndef __NET_H__
#define __NET_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MULTICAST_IP "235.10.10.3"
#define SERV_PORT 5003
#define QUIT_STR "quite"
#endif
2.3.2,sender.c
#include "net.h"
void usage(char *s)
{
printf("this is a multicast demo!
");
printf("Usage:
%s
",s);
printf(" receiver_ip: multicast_receiver ip address(between 224~239 segment)
");
printf(" receiver_port: multicast_receiver port(>5000)
");
}
int main(int argc, const char *argv[])
{
int fd;
short port;
struct sockaddr_in sin;
if(argc != 3)
{
usage((char *)argv[0]);
exit(1);
}
if((port = atoi(argv[2])) < 5000)
{
usage((char *)argv[0]);
exit(1);
}
if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
{
perror("socket");
exit(-1);
}
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
#if 0
#else
if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
#endif
printf("multicast sender starting ...... OK!
");
char buf[BUFSIZ];
while(1)
{
fprintf(stderr,"Please input the string to boardcast receiver:");
bzero(buf,BUFSIZ);
if(fgets(buf,BUFSIZ-1,stdin) == NULL)
{
perror("fgets");
continue;
}
sendto(fd,buf,strlen(buf),0,(struct sockaddr *)&sin,sizeof(sin));
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("multicast sender is existed!
");
break;
}
}
_error1:
close(fd);
return 0;
}
2.3.3,recviver.c
#include "net.h"
int main(int argc, const char *argv[])
{
int fd;
struct sockaddr_in sin;
if((fd = socket(AF_INET,SOCK_DGRAM,0)) < 0)
{
perror("socket");
exit(-1);
}
int b_reuse = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SERV_PORT);
#if 1
sin.sin_addr.s_addr = htonl(INADDR_ANY);
#else
if(inet_pton(AF_INET,SERV_IP_ADDR,(void *)&sin.sin_addr.s_addr) < 0)
{
perror("inet_pton");
goto _error1;
}
#endif
if(bind(fd,(struct sockaddr *)&sin,sizeof(sin)))
{
perror("bind");
goto _error1;
}
printf("multicast receiver starting .... OK!
");
char buf[BUFSIZ];
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
while(1)
{
bzero(buf,BUFSIZ);
if(recvfrom(fd,buf,BUFSIZ-1,0,(struct sockaddr *)&cin,&addrlen) < 0)
{
perror("recvfrom");
continue ;
}
char cin_ipv4_addr[16];
if(inet_ntop(AF_INET,&cin.sin_addr.s_addr,cin_ipv4_addr,sizeof(cin_ipv4_addr)) < 0)
{
perror("inet_ntop");
goto _error1;
}
printf("Receive multicast Data: %s",buf);
if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
{
printf("multicast sender (%s:%d) is existing!
",cin_ipv4_addr,ntohs(cin.sin_port));
}
}
_error1:
close(fd);
return 0;
}
2.3.4,运行结果
接收端
linux@linux:~/test/network/network_multicast$ ./receiver
multicast receiver starting .... OK!
Receive multicast Data: 1
Receive multicast Data: 2
Receive multicast Data: 3
Receive multicast Data: 4
Receive multicast Data: 5
Receive multicast Data: 6
Receive multicast Data: quite
multic