Linux网络编程--广播

【1】广播是一对多通信。

主机地址全1是该网段的广播地址。

广播只能发向同一个网段,并且该网段内的所有主机都可以接收。
由于广播是一对多通信,因此不能使用面向链接的流式套接字,只能使用无连接的数据报套接字。

要使用广播,需要了解IPv4特定的广播地址。可以用下面的命令来显示所选用的广播地址。
在这里插入图片描述

【2】关于setsockopt()函数
功能:
setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。

#include <sys/socket.h>
int setsockopt(int s,int level,int optname,const char *optval,int optlen);

参数:
s:标识一个套接字的描述符。
level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。
optname:需设置的选项。
optval:指针,指向存放选项值的缓冲区。
optlen:optval缓冲区长度。

返回值:
若无错误发生,setsockopt()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。

【3】广播示例–1
广播包的发送流程如下:
(1)创建UDP套接字
(2)指定目标地址和端口
(3)设置套接字选项允许发送广播包
(4)发送数据包

发送广播包代码实例:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define N 64//定义数据大小

typedef struct sockaddr SA;

int main(int argc, const char *argv[])
{
	int sockfd;//创建套接字
	char buf[N]="This is a broadcast package\n";
	int on=1;

	struct sockaddr_in dstaddr;//本地地址

	if(argc<3)
	{
	printf("Usage :<%s><ip><port>\n",argv[0]);
	return -1;
	}

	if((sockfd=socket(PF_INET,SOCK_DGRAM,0))==-1)//建立数据包套接字
	{
	perror("fail to socket");
	exit(-1);
	}

	bzero(&dstaddr,sizeof(dstaddr));//数据清零
	dstaddr.sin_family=PF_INET;//协议族
	dstaddr.sin_port=htons(atoi(argv[2]));//端口
	dstaddr.sin_addr.s_addr=inet_addr(argv[1]);//本地地址

	if(setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on))<0)//设置套接字文件描述符sock为可以进行广播
	{
	perror("fail to setsockopt");
	exit(-1);
	}

	while(1)
	{
	sendto(sockfd,buf,N,0,(SA *)&dstaddr,sizeof(dstaddr));//发送数据包
	sleep(1);
	}

	return 0;
}

接收广播包代码实例:
广播包接收流程:
(1)创建UDP套接字
(2)绑定地址和端口
(3)接收数据包

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define N 64//缓冲区大小

typedef struct sockaddr SA;

int main(int argc, const char *argv[])
{
	int sockfd;
	char buf[N];
	struct sockaddr_in myaddr,
					   peeraddr;

	socklen_t peerlen=sizeof(peeraddr);

	if(argc<3)//检查命令行参数
	{
	printf("Usage:<%s><ip><port>\n",argv[0]);
	return -1;
	}

	if((sockfd=socket(PF_INET,SOCK_DGRAM,0))==-1)      //创建套接字文件描述
	{                                                  
	perror("fail to socket");                           
	exit(-1);                                                                                      
	}    
	
	bzero(&myaddr,sizeof(myaddr));//清零
	myaddr.sin_family=PF_INET;//协议族
	myaddr.sin_port=htons(atoi(argv[2]));//端口号
	myaddr.sin_addr.s_addr=inet_addr(argv[1]);//本地地址

	if(bind(sockfd,(SA *)&myaddr,sizeof(myaddr))<0)//绑定
	{
	perror("fail to bind");
	exit(-1);
	}
	
	while(1)
	{
	recvfrom(sockfd,buf,N,0,(SA *)&peeraddr,&peerlen);//接收数据包
	printf("[%s:%d]%s\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
	}
	
	return 0;
}

【4】广播示例–2
说明:服务器在局域网上倾听,当有数据到来时候,来判断数据是否有关键字IP_FOUND,当存在此关键字,发送IP_FOUND_ACK到客户端。
客户端判断是否有服务器响应IP_FOUND请求,判断接受的字符串是否包含IP_FOUND_ACK来确定局域网是否存在服务器。

客户端:

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<time.h>
#include<string.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<pthread.h>
#include<sys/ioctl.h>
#include <net/if.h>
#define BUFF_SIZE 32//缓冲去大小
#define IP_FOUND "IP_FOUND"//ip发现命令
#define IP_FOUND_ACK "IP_FOUND_ACK"//ip发现应答命令
#define IFNAME "169.254.255.255"

int main(int argc, const char *argv[])
{
	char buff[BUFF_SIZE];
	int ret=-1;
	int sock=-1;
	int broadcastfd=-1;

	struct sockaddr_in broadcastfd_addr;//本地地址
	struct sockaddr_in from;//服务器地址
	struct ifreq ifr;

	int from_len;
	int count=-1;

	fd_set readfd;

	struct timeval timeout;//超时设置
	timeout.tv_sec =2;
	timeout.tv_usec =0;

	sock=socket(AF_INET,SOCK_DGRAM,0);//建立套接字
	if(sock<0)
	{
	perror("fail to socket");
	exit(1);
	}
	
	memcpy(ifr.ifr_name,IFNAME,strlen(IFNAME));//将需要使用的网络接口字符复制到结构中

	if(ioctl(sock,SIOCGIFBRDADDR,&ifr)==-1)//发送命令,获取网络接口广播地址
	{
	perror("fail to ioctl");
	exit(1);
	}

	memcpy(&broadcastfd_addr,&ifr.ifr_broadaddr,sizeof(struct sockaddr_in));//将获取的广播地址赋值给broadcastfd_addr
	broadcastfd_addr.sin_port=htons(7788);//设置广播端口号

	ret=setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&broadcastfd,sizeof(broadcastfd));//设置套接字文件描述符sock可以进行广播

/*主处理过程*/	
	int times=10;
	int i=10;
	for(i=0;i<times;i++)
	{
	ret=sendto(sock,IP_FOUND,strlen(IP_FOUND),0,(struct sockaddr*)&broadcastfd_addr,sizeof(broadcastfd_addr));//广播发送服务器处理请求
				if(ret==-1)
				{
				continue;
				}
	}
	
	FD_ZERO(&readfd);//文件描述符集合清零
	FD_SET(sock,&readfd);//将套接字加入集合

	ret=select(sock+1,&readfd,NULL,NULL,&timeout);//selest侦听是否有数据
	switch(ret)
	{
	case 0:	break;//超时
	case -1: break;//错误
	default:
		if(FD_ISSET(sock,&readfd))//有数据来
		{
			count=recvfrom(sock,buff,BUFF_SIZE,0,(struct sockaddr*)&from,&from_len);//接收数据
			printf("recv msg is %s\n",buff);

			if(strstr(buff,IP_FOUND_ACK))//判断是否吻合
			{
				printf("found server,IP:%d\n",inet_ntoa(from.sin_addr));
			}	
			break;//成功并退出
		}
	}
	

}




服务器端:

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<time.h>
#include<string.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<arpa/inet.h>
#include<pthread.h>
#define BUFF_SIZE 32
#define IP_FOUND "IP_FOUND"//ip发现命令
#define IP_FOUND_ACK "IP_FOUND_ACK"//ip发现应答命令
#define SERVER_ADDR "169.254.5.225"
int main(int argc, const char *argv[])
{
	char buff[BUFF_SIZE];
	int ret=-1;
	int sock=-1;
	struct sockaddr_in local;//本地地址
	struct sockaddr_in from;//客户端地址

	int from_len;
	int count=-1

	fd_set readfd;

	struct timeval timeout;//超时设置
	timeout.tv_sec =2;
	timeout.tv_usec =0;

	printf("==>HandleIPFound\n");

	sock=socket(AF_INET,SOCK_DGRAM,0);//建立数据报套接字
	if(sock<0)
	{
	perror("fail to socket");
	exit(1);
	}

	memset((void*)&local,0,sizeof(local));//数据清零
	local.sin_family=AF_INET;//协议族
	local.sin_addr.s_addr=inet_addr(SERVER_ADDR );//本地地址
	local.sin_port=htons(7788);//端口号

	if((ret==(bind(sock,(struct sockaddr*)&local,sizeof(local))))==-1)//绑定
	{
	perror("fail to bind");
	exit(1);
	}

	for(;;)
	{
	FD_ZERO(&readfd);//清空集合
	FD_SET(sock,&readfd);//将套接字文件描述符加入集合

	ret=select(sock+1,&readfd,NULL,NULL,&timeout);//select侦听是否有数据
	switch(ret)
	{
	case 0:	break;//超时
	case -1: break;//错误
	default:
		if(FD_ISSET(sock,&readfd))
		{
			count=recvfrom(sock,buff,BUFF_SIZE,0,(struct sockaddr*)&from,&from_len);//接收数据

			printf("recv msg is %s\n",buff);

			if(strstr(buff,IP_FOUND))//判断是否吻合
			{
				memcpy(buff,IP_FOUND_ACK,strlen(IP_FOUND_ACK)+1);//复制数据
				count=sendto(sock,buff,strlen(buff),0,(struct sockaddr*)&from,from_len);//发送给客户端
			}	

		}
	}
	}
	
	printf("<==HandleIPFound\n");
	return;
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值