linux 广播

广播是一台主机向局域网内的所有主机发送数据。这时,同一网段的所有主机都能接收到数据。发送广播包的步骤大致如下:

(1)确定一个发送广播的接口,如eth0

(2)确定广播的地址,通过ioctl函数,请求码设置为SIOCGIFBRDADDR得到广播的地址

(3)使用这个广播地址进行广播

在局域网内,广播通常用来探测服务器。

广播发送端:

  1 主机:
  2 
  3 #include<stdio.h>
  4 #include<stdlib.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #include<sys/socket.h>
  8 #include<arpa/inet.h>
  9 #include<netinet/in.h>
 10 #include<sys/types.h>
 11 #include<netdb.h>
 12 #include <sys/ioctl.h>
 13 #include <net/if.h>
 14 /**
 15 客户端实现广播
 16 
 17 
 18 **/
 19 #define IP_FOUND "IP_FOUND"
 20 #define IP_FOUND_ACK "IP_FOUND_ACK"
 21 #define IFNAME "eth0"
 22 #define MCAST_PORT 9999
 23 int main(int argc,char*argv[]){
 24 int ret=-1;
 25 
 26 
 27 struct sockaddr_in from_addr;//服务端地址
 28 int from_len=sizeof(from_addr);
 29 int count=-1;
 30 fd_set readfd;//读文件描述符集合
 31 char buffer[1024];
 32 struct timeval timeout;
 33 timeout.tv_sec=2;//超时时间为2秒
 34 timeout.tv_usec=0;
 35 
 36 int sock=-1;
 37 sock=socket(AF_INET,SOCK_DGRAM,0);//建立数据报套接字
 38 if(sock<0){
 39   printf("HandleIPFound:sock init error
");
 40   return;
 41 }
 42 
 43 
 44 //将使用的网络接口名字复制到ifr.ifr_name中,由于不同的网卡接口的广播地址是不一样的,因此指定网卡接口
 45 
 46 struct ifreq ifr;
 47 strncpy(ifr.ifr_name,IFNAME,strlen(IFNAME));
 48 //发送命令,获得网络接口的广播地址
 49 if(ioctl(sock,SIOCGIFBRDADDR,&ifr)==-1){
 50     perror("ioctl error");
 51     return;
 52 }
 53 
 54 //将获得的广播地址复制到broadcast_addr
 55 int so_broadcast=1;
 56 struct sockaddr_in broadcast_addr;//广播地址
 57 memcpy(&broadcast_addr,&ifr.ifr_broadaddr,sizeof(struct sockaddr_in));
 58 
 59 
 60 //设置广播端口号
 61 printf("broadcast IP is:%s
",inet_ntoa(broadcast_addr.sin_addr));
 62 broadcast_addr.sin_family=AF_INET;
 63 broadcast_addr.sin_port=htons(MCAST_PORT);
 64 //默认的套接字描述符sock是不支持广播,必须设置套接字描述符以支持广播
 65 ret=setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&so_broadcast,sizeof(so_broadcast));
 66 
 67 
 68 
 69 //发送多次广播,看网络上是否有服务器存在
 70 int times=10;
 71 int i=0;
 72 for(i=0;i<times;i++){//一共发送10次广播,每次等待2秒是否有回应
 73   //广播发送服务器地址请求
 74     timeout.tv_sec=2;//超时时间为2秒
 75         timeout.tv_usec=0;
 76     ret=sendto(sock,IP_FOUND,strlen(IP_FOUND),0,(struct sockaddr*)&broadcast_addr,sizeof(broadcast_addr));
 77     if(ret==-1){
 78         continue;
 79     }
 80 
 81 //文件描述符清0
 82 FD_ZERO(&readfd);
 83 //将套接字文件描述符加入到文件描述符集合中
 84 FD_SET(sock,&readfd);
 85 //select侦听是否有数据到来
 86 ret=select(sock+1,&readfd,NULL,NULL,&timeout);
 87 switch(ret){
 88  case -1:
 89     break;
 90  case 0:
 91     printf("timeout
");
 92     break;
 93  default:
 94 //接收到数据
 95  if(FD_ISSET(sock,&readfd)){
 96     count=recvfrom(sock,buffer,1024,0,(struct sockaddr*)&from_addr,&from_len);//from_addr为服务器端地址
 97     printf("recvmsg is %s
",buffer);
 98     if(strstr(buffer,IP_FOUND_ACK)){
 99         printf("found server IP is:%s
",inet_ntoa(from_addr.sin_addr));
100         //服务器端的发送端口号
101         printf("Server Port:%d
",htons(from_addr.sin_port));
102     }
103   return;
104     
105 }
106  break;
107 
108 }
109 }
110 return;
111 }

广播接收端:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <sys/types.h>
 4 #include <sys/socket.h>
 5 #include <fcntl.h>
 6 #include <linux/in.h>
 7 #include <stdlib.h>
 8 /**
 9 广播接收端代码
10 **/
11 #define IP_FOUND "IP_FOUND"
12 #define IP_FOUND_ACK "IP_FOUND_ACK"
13 #define PORT 9999
14 int main(int argc,char*argv[]){
15  int ret=-1;
16  int sock;
17  struct sockaddr_in server_addr;//服务器端地址
18  struct sockaddr_in from_addr;//客户端地址
19  int from_len=sizeof(struct sockaddr_in);
20  int count=-1;
21  fd_set readfd;//读文件描述符集合
22  char buffer[1024];
23  struct timeval timeout;
24  timeout.tv_sec=2;
25  timeout.tv_usec=0;
26  sock=socket(AF_INET,SOCK_DGRAM,0);//建立数据报套接字
27  if(sock<0){
28     perror("sock error");
29     return;
30 }
31 
32 memset((void*)&server_addr,0,sizeof(struct sockaddr_in));
33 server_addr.sin_family=AF_INET;
34 server_addr.sin_addr.s_addr=htons(INADDR_ANY);
35 server_addr.sin_port=htons(PORT);
36 //将地址结构绑定到套接字上./
37 ret=bind(sock,(struct sockaddr*)&server_addr,sizeof(server_addr));
38 if(ret<0){
39     perror("bind error");
40     return;
41 }
42 
43 while(1){
44 timeout.tv_sec=2;
45 timeout.tv_usec=0;
46 //文件描述符集合清0
47 FD_ZERO(&readfd);
48 //将套接字描述符加入到文件描述符集合
49 FD_SET(sock,&readfd);
50 //select侦听是否有数据到来
51 ret=select(sock+1,&readfd,NULL,NULL,&timeout);//侦听是否可读
52 printf("ret=%d
",ret);
53 switch(ret){
54 case -1://发生错误
55 break;
56 case 0://超时
57 printf("timeout
");
58 break;
59 default:
60 if(FD_ISSET(sock,&readfd)){
61     count=recvfrom(sock,buffer,1024,0,(struct sockaddr*)&from_addr,&from_len);//接收客户端发送的数据
62     //from_addr保存客户端的地址结构
63     if(strstr(buffer,IP_FOUND)){
64         //响应客户端请求
65         //打印客户端的IP地址
66             printf("Client IP is%s
",inet_ntoa(from_addr.sin_addr));
67         //打印客户端的端口号
68         printf("Client Send Port:%d
",ntohs(from_addr.sin_port));
69         memcpy(buffer,IP_FOUND_ACK,strlen(IP_FOUND_ACK)+1);
70         count=sendto(sock,buffer,strlen(buffer),0,(struct sockaddr*)&from_addr,from_len);//将数据发送给客户端
71     }
72  return;
73 }
74 break;
75 }
76 }
77 return;
78 }

转自:

http://blog.csdn.net/chenjin_zhong/article/details/7270213

原文地址:https://www.cnblogs.com/meizixiong/p/3228182.html