网络通信--广播C/S

◆广播和多播只能由UDP传输协议实现,不支持TCP; 

◆广播只支持IPv4,不支持IPv6。而多播IPv4、IPv6都支持。所以IPv4的广播程序要移植到IPv6的环境下,要用多播实现

由于TCP协议是端到端的协议,在通信之前,必须建立连接,三次握手之后才能发送数据。而广播是一对多的通信,所以TCP不支持广播。在局域网内,广播通常用来探测服务器。

ser:

 1 /*服务器广播*/
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <sys/types.h>
 5 #include <sys/socket.h>
 6 #include <fcntl.h>
 7 #include <linux/in.h>
 8 #include <stdlib.h>
 9 
10 #define PORT 2345
11 #define SIZE 1024
12 #define BROARDCAST_SUCCESS "Broadcast OK!"
13 
14 char *ser_broadcast()
15 {
16     int ret;
17     int sock;
18     int sockaddr_len;
19     struct sockaddr_in ser_addr;
20     struct sockaddr_in cli_addr;
21     struct timeval time;
22     fd_set fd_read;
23     char buf[SIZE];
24 
25     //创建套接字
26     sockaddr_len = sizeof(struct sockaddr_in);
27     sock = socket(AF_INET, SOCK_DGRAM, 0);
28     if(sock < 0) {
29         perror("sock error");
30         exit(-1);
31     }
32 
33     /*设置地址可重用*/
34     int opt = 1;
35     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
36 
37     /*INADDR_ANY就是指定地址为0.0.0.0的地址,
38     这个地址事实上表示不确定地址,或“所有地址”、“任意地址” */
39     memset(&ser_addr, 0, sockaddr_len);
40     ser_addr.sin_family = AF_INET;
41     ser_addr.sin_addr.s_addr = htons(INADDR_ANY);
42     ser_addr.sin_port = htons(PORT);
43 
44     //绑定广播服务端套接口
45     ret = bind(sock, (struct sockaddr*)&ser_addr, sockaddr_len);
46     if(ret < 0) {
47         perror("bind error");
48         exit(-1);
49     }
50 
51     while(1)
52     {
53         time.tv_sec = 2;
54         time.tv_usec = 0;
55 
56         FD_ZERO(&fd_read);
57         FD_SET(sock, &fd_read);
58     
59         //定时查看服务端套接口是否可读
60         ret = select(sock+1, &fd_read, NULL, NULL, &time);
61         printf("ret=%d
", ret);
62         switch(ret)
63         {
64             case -1:
65                 perror("select error");
66                 break;
67             case 0:
68                 printf("timeout!
");
69                 break;
70             default:
71                 if(FD_ISSET(sock, &fd_read))
72                 {
73                     recvfrom(sock, buf, SIZE, 0,
74                             (struct sockaddr*)&cli_addr, &sockaddr_len); 
75                     printf("from client msg :%s
", buf);
76                     printf("from client ip  :%s
", inet_ntoa(cli_addr.sin_addr));
77                     printf("from client port:%d
", ntohs(cli_addr.sin_port));
78                     strcpy(buf, BROARDCAST_SUCCESS);
79                     sendto(sock, buf, strlen(buf), 0,
80                             (struct sockaddr*)&cli_addr, sockaddr_len);
81                 }
82                 return 0;
83         }
84     }
85 
86     return 0;
87 }
88 
89 int main()
90 {
91     ser_broadcast();
92 
93     return 0;
94 }

cli:

  1 /*客户端广播*/
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<string.h>
  6 #include<sys/socket.h>
  7 #include<arpa/inet.h>
  8 #include<netinet/in.h>
  9 #include<sys/types.h>
 10 #include<netdb.h>
 11 #include <sys/ioctl.h>
 12 #include <net/if.h>
 13 
 14 #define PORT 2345
 15 #define SIZE 1024
 16 #define IFNAME "eth0"
 17 
 18 char getip[16];
 19 
 20 //若该端口有服务器,成功获得服务器IP
 21 char *cli_broadcast(char *getip)
 22 {
 23     int ret;
 24     int sock;
 25     int count = 1;
 26     int times = 5;
 27     int sockaddr_len;
 28     int so_broadcast = 1;
 29 
 30     struct timeval time;
 31     struct ifreq ifr;
 32     struct sockaddr_in bcast_addr;
 33     struct sockaddr_in cli_addr;
 34     struct sockaddr_in ser_addr;
 35 
 36     fd_set fd_read;
 37     char buf[1024] = "BROADCAST!";
 38 
 39     sockaddr_len = sizeof(struct sockaddr_in);
 40     sock = socket(AF_INET, SOCK_DGRAM, 0);
 41     if(socket < 0) {
 42         perror("socket error");
 43         exit(-1);
 44     }
 45 
 46     strcpy(ifr.ifr_name, IFNAME);
 47 //获得网络接口的广播地址
 48     if(ioctl(sock, SIOCGIFBRDADDR, &ifr) == -1) {
 49         perror("ioctl error");
 50         exit(-1);
 51     }
 52 
 53 //将获得的广播地址复制到bcast_addr
 54     memcpy(&bcast_addr, &ifr.ifr_broadaddr, sockaddr_len);
 55     bcast_addr.sin_family = AF_INET;
 56     bcast_addr.sin_port = htons(PORT);
 57 //    printf("broadcast ip is:%s
", inet_ntoa(bcast_addr.sin_addr));
 58 //    printf("broadcast port is:%d
", ntohs(bcast_addr.sin_port));
 59 
 60 //默认的套接字描述符sock是不支持广播,必须设置套接字描述符以支持广播
 61     ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so_broadcast, 4);
 62     if(ret == -1) {
 63         perror("setsockopt error");
 64         exit(-1);
 65     }
 66 
 67 
 68     while(times--) {
 69         ret = sendto(sock, buf, strlen(buf), 0,
 70                     (struct sockaddr*)&bcast_addr, sockaddr_len);
 71         if(ret == -1) {
 72             perror("sendto");
 73             continue;
 74         }
 75         printf("send times=%d
", count++);
 76 
 77         time.tv_sec = 2;   //该定时器需要重新填入时间
 78         time.tv_usec = 0;
 79 
 80         FD_ZERO(&fd_read); //该文件描述集也要重新安装
 81         FD_SET(sock, &fd_read);
 82 
 83         //客户端套接口是否可读
 84         ret = select(sock+1, &fd_read, NULL, NULL, &time);
 85         switch(ret) {
 86             case -1:
 87                 perror("select error!");
 88                 break;
 89             case 0:
 90                 printf("timeout!
");
 91                 break;
 92             default:
 93                 if(FD_ISSET(sock, &fd_read)) {
 94                     recvfrom(sock, buf, SIZE, 0,
 95                             (struct sockaddr*)&ser_addr, &sockaddr_len);
 96                     printf("from server msg :%s
", buf);
 97                     printf("from server ip  :%s
", inet_ntoa(ser_addr.sin_addr));
 98                     printf("from server port:%d
", ntohs(ser_addr.sin_port));
 99                     strcpy(getip, inet_ntoa(ser_addr.sin_addr));
100                 }
101                 return ;
102         }
103     }
104 
105     return NULL;
106 }
107 
108 int main()
109 {
110     cli_broadcast(getip);
111     printf("Get service ip=%s
", getip);
112 
113     return 0;
114 }

运行结果:

原文地址:https://www.cnblogs.com/kaijia9/p/3400980.html