广播:
1.主机之间一对多的通信模式,网络对其中的每一台主机发出的信息都进行无条件复制并转发。
2.所有主机都可以接收到广播信息(不管你是否需要)
3.禁止广播数据穿过:路由器(只能做局域网内通信),防止广播数据影响大面积主机。4.只有UDP能广播。
5.广播地址:有效网络号+全是1的主机号
a.192.168.8.123 ---> 192.168.8.255
b.255.255.255.255:给所有网段中的所有主机发送广播,但是无法穿过路由器,所以只能做局域网内通信。
>>广播发送方
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line: %d",__LINE__);\
perror(msg);\
}while(0)
#define SER_IP "192.168.0.255"//广播ip ifconfig
#define SER_PORT 6666 //1024-49151之间任意数
int main(int argc, const char *argv[])
{
//创建报式套接字
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd<0)
{
ERR_MSG("socket");
return -1;
}
//设置允许广播
int broad=1;
if(setsockopt(cfd,SOL_SOCKET,SO_BROADCAST,&broad,sizeof(broad))<0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("set broadcast success\n");
//绑定bind 非必须绑定
//如果不绑定则由操作系统自动绑定ip和端口
//填充接受方信息结构体信息,给sendto函数使用
struct sockaddr_in sin;
sin.sin_family=AF_INET;//必须填AF_INET
sin.sin_port=htons(SER_PORT);//端口号的网络字节序
sin.sin_addr.s_addr=inet_addr(SER_IP);//广播ip地址
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
printf("请输入>>>");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
//发送数据
res = sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
}
//关闭文件描述符
close(cfd);
return 0;
}
>>广播接收方
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line: %d",__LINE__);\
perror(msg);\
}while(0)
#define SER_IP "192.168.0.255"//广播ip ifconfig
#define SER_PORT 6666 //1024-49151之间任意数
int main(int argc, const char *argv[])
{
//创建报式套接字
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd<0)
{
ERR_MSG("socket");
return -1;
}
//填充接受方自身信息结构体信息
struct sockaddr_in sin;
sin.sin_family=AF_INET; //必须填AF_INET
sin.sin_port=htons(SER_PORT); //端口号的网络字节序
sin.sin_addr.s_addr=inet_addr(SER_IP);//广播ip地址
//绑定,必须绑定
if(bind(cfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
//数据包是从谁那里来的
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
//接收数据
res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("[%s : %d]:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),buf);
}
//关闭文件描述符
close(cfd);
return 0;
}
>>>>组播发送方
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line: %d",__LINE__);\
perror(msg);\
}while(0)
#define GRP_IP "224.1.1.1"//224.0.0.0-239.255.255.255
#define PORT 6666 //1024-49151之间任意数
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
//填充接收方的地址信息结构体,给sendto函数使用
struct sockaddr_in sin;
sin.sin_family=AF_INET;//必须填AF_INET
sin.sin_port=htons(PORT);//端口号网络字节序
sin.sin_addr.s_addr=inet_addr(GRP_IP);//ip地址
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
printf("请输入>>>");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
//发送数据,发给服务器
res=sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
if(res<0)
{
ERR_MSG("sendto");
return -1;
}
printf("发送成功\n");
}
//关闭文件描述符
close(sfd);
return 0;
}
>>>>>组播接收方
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line: %d",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.0.13"//本机ip ifconfig
#define GRP_IP "224.1.1.1" //组播ip 224.0.0.0-239.255.255.255
#define PORT 6666 //1024-49151之间任意数
int main(int argc, const char *argv[])
{
//创建报式套接字
int cfd=socket(AF_INET,SOCK_DGRAM,0);
if(cfd<0)
{
ERR_MSG("socket");
return -1;
}
//加入多播组
struct ip_mreqn mq;
mq.imr_multiaddr.s_addr=inet_addr(GRP_IP);//组播ip
mq.imr_address.s_addr=inet_addr(IP);//本机ip
mq.imr_ifindex=0;
if(setsockopt(cfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mq,sizeof(mq))<0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("加入多播组成功\n");
//填充接收方地址信息结构体
struct sockaddr_in cin;
cin.sin_family=AF_INET;//必须填AF_INET
cin.sin_port=htons(PORT);//端口号网络字节序
cin.sin_addr.s_addr=inet_addr(GRP_IP);//组播ip地址,与加入的组播ip一致
//绑定,必须绑定
if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin))<0)
{
ERR_MSG("bind");
return -1;
}
//数据包从哪来的
struct sockaddr_in sin;
socklen_t addrlen=sizeof(sin);
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
//接收数据,必须接收数据包发送方地址信息,给sendto使用
res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&addrlen);
//res = recv(cfd,buf,sizeof(buf),0)
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("addr:[%s]port:[%d] %s\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port),buf);
}
close(cfd);
return 0;
}