广播UDP与单播UDP的区别就是IP地址不同,广播使用广播地址xxx.xxx.xxx.255,将消息发送到在同一广播网络上的每个主机,广播/组播只能用udp进行实现
函数:int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_toptlen);
参数:
sockfd:要设置的套接字描述符。
level:选项定义的层次。或为特定协议的代码(如IPv4,IPv6,TCP,SCTP),或为通用套接字代码(SOL_SOCKET)。
optname:选项名。level对应的选项,一个level对应多个选项,不同选项对应不同功能。
optval:指向某个变量的指针,该变量是要设置新值的缓冲区。可以是一个结构体,也可以是普通变量
optlen:optval的长度。
关于optname的可选项,根据你需要的功能进行设置
当leve为SOL_SOCKET时,optname可以有以下选项(一部分)
SO_BROADCAST 允许发送广播数据 int
SO_DEBUG 允许调试 int
SO_LINGER 延迟关闭连接 struct linger
SO_OOBINLINE 带外数据放入正常数据流 int
SO_RCVBUF 接收缓冲区大小 int
SO_SNDBUF 发送缓冲区大小 int
SO_RCVLOWAT 接收缓冲区下限 int
SO_SNDLOWAT 发送缓冲区下限 int
SO_RCVTIMEO 接收超时 struct timeval
SO_SNDTIMEO 发送超时 struct timeval
流程:socket---setsockopt----sendto---close 值得注意的是 你的接收端必须和发送端保持一致的端口号,用广播地址进行发送,只要在同一局域网,且端口号一致的,都会收到发送端的消息,广播地址可以用ifconfig进行查看,接收方只需要接收就行了
出现的错误:发送端和接收端没有问题,但接收端死活接收不到消息,用准确的ip地址发就可以,用广播地址就是接收不到消息,后面我把接收端的ip地址改成:INADDR_ANY ,就可以
INADDR_ANY:表示本机上所有的ip地址,转换过来就是0.0.0.0,因为电脑不止一块网卡。多网卡情况下,ip地址也就多了
udp广播 发送端
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
void main(int argc,char ** argv)
{
if(argc != 3)
{
printf("argc error!\n");
exit(-1);
}
int fd;
char buf[128];
struct sockaddr_in client;
//1.socket
fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd < 0)
{
perror("socket");
}
else
printf("socket succeed!\n");
//2.setsockopt
int so_broadcast = 1;
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &so_broadcast, sizeof(so_broadcast));//SO_BROADCAST:为配置广播选项,
// so_broadcast :0,关闭广播;1:开
启广播
client.sin_family = AF_INET;
client.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&client.sin_addr);
//3.sendto
while(1)
{
memset(buf,'\0',sizeof(buf));
printf("请输入您要发的消息:");
gets(buf);
if(!strncasecmp(buf,"quit",4))
{
break;
}
sendto(fd,buf,sizeof(buf),0,(struct sockaddr *)&client,sizeof(client));
}
printf("客户端已退出-----\n");
//4.close
close(fd);
}
组播弥补了广播的不足,他是将想要收到消息的主机,通过组播地址加入到这个组播,只有加入了组播的主机,才会收到消息,组播地址范围:224.0.0.0 到 239.255.255.255
流程:socket--bind-- 加入多播组(结构体)---setsockopt(打开组播)---recvfrom---close
发送端只需要和接收端保持一致的端口号,用组播地址进行发送,加入到组播的主机就会收到消息
struct ip_mreq
{
struct in_addr imn_multiaddr; // 多播组 IP,
struct in_addr imr_interface; // 将谁的IP添加到多播组
};
组播接收端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SIZE 128
void main(int argc,char **argv)
{
int fd;
int bFlag;
char buf[128];
struct sockaddr_in server;
struct sockaddr_in client;
//1.socket
fd = socket(AF_INET,SOCK_DGRAM,0);
if(fd < 0)
{
printf("socket error!\n");
}
else
printf("socket succeed!\n");
//2.bind
server.sin_family = AF_INET;
server.sin_port = htons(8881);
//inet_aton(argv[1],&server.sin_addr);
server.sin_addr.s_addr = INADDR_ANY;
bFlag = bind(fd,(struct sockaddr *)&server,sizeof(struct sockaddr_in));
if(bFlag < 0)
{
printf("绑定失败\n");
}
else
printf("绑定成功!\n");
//3.加入多播组
struct ip_mreq zuBo;//组播相关的结构体
zuBo.imr_multiaddr.s_addr = inet_addr("224.0.0.1");//加入多播组 224.0.0.1~239.255.255.254
zuBo.imr_interface.s_addr = INADDR_ANY;//本机加入多播组
//4.设置网络属性 setsockopt
int req = 1;
setsockopt(fd,IPPROTO_IP,IP_DROP_MEMBERSHIP,&req,sizeof(req));
//5.recvfrom
while(1)
{
memset(buf,'\0',sizeof(buf));
recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&client,sizeof(client));
printf("来自组播:%s:%s\n",inet_ntoa(client.sin_addr),buf);
}
//6.close
}