廣播是一台主機向局域網內的所有主機發送數據。這時,同一網段的所有主機都能接收到數據。發送廣播包的步驟大致如下:
(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\n"); 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\n",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\n"); 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\n",buffer); 98 if(strstr(buffer,IP_FOUND_ACK)){ 99 printf("found server IP is:%s\n",inet_ntoa(from_addr.sin_addr)); 100 //服務器端的發送端口號 101 printf("Server Port:%d\n",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\n",ret); 53 switch(ret){ 54 case -1://發生錯誤 55 break; 56 case 0://超時 57 printf("timeout\n"); 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\n",inet_ntoa(from_addr.sin_addr)); 67 //打印客戶端的端口號 68 printf("Client Send Port:%d\n",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