网络通信--广播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\n", ret);
62 switch(ret)
63 {
64 case -1:
65 perror("select error");
66 break;
67 case 0:
68 printf("timeout!\n");
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\n", buf);
76 printf("from client ip :%s\n", inet_ntoa(cli_addr.sin_addr));
77 printf("from client port:%d\n", 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\n", inet_ntoa(bcast_addr.sin_addr));
58 // printf("broadcast port is:%d\n", 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\n", 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!\n");
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\n", buf);
97 printf("from server ip :%s\n", inet_ntoa(ser_addr.sin_addr));
98 printf("from server port:%d\n", 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\n", getip);
112
113 return 0;
114 }
运行结果: