11.2.3 广播的示例
来源:互联网 发布:dnf韩服改版技能数据 编辑:程序博客网 时间:2024/05/01 17:50
11.2.3 广播的示例
本节中是一个服务器地址发现的代码,假设服务器为A,客户端为B。客户端在某个局域网启动的时候,不知道本局域网内是否有适合的服务器存在,它会使用广播在本局域网内发送特定协议的请求,如果有服务器响应了这种请求,则使用响应请求的IP地址进行连接,这是一种服务器/客户端自动发现的常用方法。
1.广播例子简介
如图11.5所示为使用广播的方法发现局域网上服务器的IP地址。服务器在局域网上侦听,当有数据到来的时候,判断数据是否有关键字IP_FOUND,当存在此关键字的时候,发送IP_FOUND_ACK到客户端。客户端判断是否有服务器的响应IP_FOUND请求,并判断响应字符串是否包含IP_FOUND_ACK来确定局域网上是否存在服务器,如果有服务器的响应,则根据recvfrom()函数的from变量可以获得服务器的IP地址。
图11.5 利用广播进行服务器IP地址的发现
2.广播的服务器端代码
服务器的代码如下,服务器等待客户端向某个端口发送数据,如果数据的格式正确,则服务器会向客户端发送响应数据。
01
02 #define IP_FOUND "IP_FOUND" /*IP发现命令*/
03 #define IP_FOUND_ACK "IP_FOUND_ACK" /*IP发现应答命令*/
04 void HandleIPFound(void*arg)
05 {
06 #define BUFFER_LEN 32
07 int ret = -1;
08 SOCKET sock = -1;
09 struct sockaddr_in local_addr; /*本地地址*/
10 struct sockaddr_in from_addr; /*客户端地址*/
11 int from_len;
12 int count = -1;
13 fd_set readfd;
14 char buff[BUFFER_LEN];
15 struct timeval timeout;
16 timeout.tv_sec = 2; /*超时时间2s*/
17 timeout.tv_usec = 0;
18
19 DBGPRINT("==>HandleIPFound/n");
20
21 sock = socket(AF_INET, SOCK_DGRAM, 0); /*建立数据报套接字*/
22 if( sock < 0 )
23 {
24 DBGPRINT("HandleIPFound: socket init error/n");
25 return;
26 }
27
28 /*数据清零*/
29 memset((void*)&local_addr, 0, sizeof(struct sockaddr_in));
/*清空内存内容*/
30 local_addr.sin_family = AF_INET; /*协议族*/
31 local_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*本地地址*/
32 local_addr.sin_port = htons(MCAST_PORT); /*侦听端口*/
33 /*绑定*/
34 ret = bind(sock, (struct sockaddr*)&local_addr, sizeof(local_
addr));
35 if(ret != 0)
36 {
37 DBGPRINT("HandleIPFound:bind error/n");
38 return;
39 }
40
41 /*主处理过程*/
42 while(1)
43 {
44 /*文件描述符集合清零*/
45 FD_ZERO(&readfd);
46 /*将套接字文件描述符加入读集合*/
47 FD_SET(sock, &readfd);
48 /*select侦听是否有数据到来*/
49 ret = selectsocket(sock+1, &readfd, NULL, NULL, &timeout);
50 switch(ret)
51 {
52 case -1:
53 /*发生错误*/
54 break;
55 case 0:
56 /*超时*/
57 //超时所要执行的代码
58
59 break;
60 default:
61 /*有数据到来*/
62 if( FD_ISSET( sock, &readfd ) )
63 {
64 /*接收数据*/
65 count = recvfrom( sock, buff, BUFFER_LEN, 0,
( struct sockaddr*) &from_addr, &from_len );
66 DBGPRINT( "Recv msg is %s/n", buff );
67 if( strstr( buff, IP_FOUND ) )
/*判断是否吻合*/
68 {
69 /*将应答数据复制进去*/
70 memcpy(buff, IP_FOUND_ACK,strlen(IP_
FOUND_ACK)+1);
71 /*发送给客户端*/
72 count = sendto( sock, buff, strlen( buff ),
0, ( struct sockaddr*) &from_addr, from_
len );
73 }
74 }
75 }
76 }
77 PRINT("<==HandleIPFound/n");
78
79 return;
80 }
服务器端分为如下步骤:
q 第16行和第17行定义了服务器等待的超时时间,为2s。
q 第29行将地址结构清零。
q 第30行定义地址协议族为AF_INET。
q 第31行设置IP地址为任意本地地址。
q 第32行设置侦听的端口。
q 第34行将本地的地址绑定到一个套接字文件描述符上。
q 第42行开始为主处理过程,使用select函数,按照2s的超时时间侦听是否有数据到来。
q 第45行文件描述符集合清零。
q 第47行将套接字文件描述符加入读集合。
q 第49行select侦听是否有数据到来。
q 第50行查看select的返回值。
q 第52行select发生错误。
q 第55行select超时。
q 第60行有可读的数据到来。
q 第65行接收数据。
q 第67行查看接收到的数据是否匹配。
q 第70行复制响应数据。
q 第72行发送响应数据到客户端。
3.广播的客户端代码
广播的客户端函数代码如下,客户端向服务器端发送命令IP_FOUND,并等待服务器端的回复,如果有服务器回复,则向服务器发送IP_FOUND_ACK,否则发送10遍后退出。
01 #define IP_FOUND "IP_FOUND" /*IP发现命令*/
02 #define IP_FOUND_ACK "IP_FOUND_ACK" /*IP发现应答命令*/
03 #define IFNAME "eth0"
04 void IPFound(void*arg)
05 {
06 #define BUFFER_LEN 32
07 int ret = -1;
08 SOCKET sock = -1;
09 int so_broadcast = 1;
10 struct ifreq ifr;
11 struct sockaddr_in broadcast_addr; /*本地地址*/
12 struct sockaddr_in from_addr; /*服务器端地址*/
13 int from_len;
14 int count = -1;
15 fd_set readfd;
16 char buff[BUFFER_LEN];
17 struct timeval timeout;
18 timeout.tv_sec = 2; /*超时时间2s*/
19 timeout.tv_usec = 0;
20
21
22 sock = socket(AF_INET, SOCK_DGRAM, 0);/*建立数据报套接字*/
23 if( sock < 0 )
24 {
25 DBGPRINT("HandleIPFound: socket init error/n");
26 return;
27 }
28 /*将需要使用的网络接口字符串名字复制到结构中*/
29 strcpy(ifr.ifr_name,IFNAME,strlen(IFNAME));
30 /*发送命令,获取网络接口的广播地址*/
31 if(ioctl(sock,SIOCGIFBRDADDR,&ifr) == -1)
32 perror("ioctl error"),exit(1);
33 /*将获得的广播地址复制给变量broadcast_addr*/
34 memcpy(&broadcast_addr, &ifr.ifr_broadaddr, sizeof(struct
sockaddr_in ));
35 broadcast_addr.sin_port = htons(MCAST_PORT);/*设置广播端口*/
36
37 /*设置套接字文件描述符sock为可以进行广播操作*/
38 ret = setsockopt(sock,
39 SOL_SOCKET,
40 SO_BROADCAST,
41 &so_broadcast,
42 sizeof so_broadcast);
43
44 /*主处理过程*/
45 int times = 10;
46 int i = 0;
47 for(i=0;i<times;i++)
48 {
49 /*广播发送服务器地址请求*/
50 ret = sendto(sock,
51 IP_FOUND,
52 strlen(IP_FOUND),
53 0,
54 (struct sockaddr*)&broadcast_addr,
55 sizeof(broadcast_addr));
56 if(ret == -1){
57 continue;
58 }
59 /*文件描述符集合清零*/
60 FD_ZERO(&readfd);
61 /*将套接字文件描述符加入读集合*/
62 FD_SET(sock, &readfd);
63 /*select侦听是否有数据到来*/
64 ret = selectsocket(sock+1, &readfd, NULL, NULL, &timeout);
65 switch(ret)
66 {
67 case -1:
68 /*发生错误*/
69 break;
70 case 0:
71 /*超时*/
72 //超时所要执行的代码
73
74 break;
75 default:
76 /*有数据到来*/
77 if( FD_ISSET( sock, &readfd ) )
78 {
79 /*接收数据*/
80 count = recvfrom( sock, buff, BUFFER_LEN, 0,
( struct sockaddr*) &from_addr, &from_len );
81 DBGPRINT( "Recv msg is %s/n", buff );
82 if(strstr(buff, IP_FOUND_ACK))/*判断是否吻合*/
83 {
84 printf("found server, IP is %s/n",inet_ntoa
(from_addr.sin_addr));
85 }
86 break;/*成功获得服务器地址,退出*/
07 }
08 }
09 }
90 return;
91 }
客户端分为如下步骤:
q 第18行和第19行定义了服务器等待的超时时间,为2s。
q 第22行建立数据报套接字。
q 第29行复制网络接口名称。
q 第31行获得与网络接口名称对应的广播地址。
q 第34行和第35行设置广播的地址和端口。
q 第38~42行设置可广播地址,因为默认情况下是不可广播的。
q 第47行开始为主处理过程,发送多次广播数据,查看网络上是否有服务器存在。
q 第50~55行发送服务器请求到整个局域网上。
q 第60行文件描述符集合清零。
q 第62行将套接字文件描述符加入读集合。
q 第64行select侦听是否有数据到来。
q 第65行查看select的返回值。
q 第67行select发生错误。
q 第70行select超时。
q 第75行有可读的数据到来。
q 第65行接收数据。
q 第80行查看接收到的数据是否匹配。
- 11.2.3 广播的示例
- Android 广播的用法示例
- Android 广播的用法示例
- C#的UDP广播通信程序示例
- 一个VC简单的UDP广播示例
- 非常简单的android广播示例
- 跨应用之间的广播安全-示例
- rocket mq 的广播模式示例
- 16 UDP广播示例
- android监控SIM卡状态的广播示例代码
- C语言socket UDP广播的发送和接收示例
- Android中 广播发送 和 接受 的简单示例
- 广播的无序广播
- java udp广播代码示例
- Android静态,动态广播示例
- Android静态,动态广播示例
- Qt UDP 广播简单示例
- BroadcastReceiver广播接听器的初步认识,广播优先级,中断,权限,广播暴露(3)
- 展开/收缩DIV层面板(Open/Close Div Layers)
- org.hibernate.TransientObjectException: object references an unsaved transient instance
- 【转】ajax和IE7、IE8的问题
- 关于ListBox某一列响应,产生对话框
- 很多学习资料的IBM网
- 11.2.3 广播的示例
- ASP递归无极限菜单树
- SendMessage函数使用说明(转)
- MIME协议
- 喀嚓鱼”马克杯活动,我无语了
- 11.3 多 播
- VC调用COM的方式总结
- 11.3.1 多播的概念
- 管理信息系统的开发过程