11.2.3 广播的示例

本文介绍了一种通过广播寻址机制实现服务器自动发现的方法。客户端发送广播请求,服务器响应以确认其存在并提供IP地址。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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      49select侦听是否有数据到来。

q      50行查看select的返回值。

q      52select发生错误。

q      55select超时。

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      3842行设置可广播地址,因为默认情况下是不可广播的。

q      47行开始为主处理过程,发送多次广播数据,查看网络上是否有服务器存在。

q      5055行发送服务器请求到整个局域网上。

q      60行文件描述符集合清零。

q      62行将套接字文件描述符加入读集合。

q      64select侦听是否有数据到来。

q      65行查看select的返回值。

q      67select发生错误。

q      70select超时。

q      75行有可读的数据到来。

q      65行接收数据。

q      80行查看接收到的数据是否匹配。

### 回答1: Big Sur 11.2.3是苹果公司最新发布的操作系统版本之一,针对这个版本的镜像下载,可以通过以下几种方式进行: 1. 官方渠道下载:在苹果官方网站上,可以找到最新的操作系统版本下载链接。在"Safari"浏览器中,访问苹果官网,搜索"Big Sur 11.2.3下载",进入相关页面,找到下载链接,点击下载即可。 2. 开发者渠道下载:若你是一位开发者,可以通过苹果的开发者中心或者Xcode软件进行下载。首先登陆开发者中心,找到对应的开发者工具,下载安装后即可获取镜像文件。 3. 第三方镜像网站:也可以通过一些第三方镜像网站进行下载,这些网站会提供已经制作好的Big Sur 11.2.3镜像文件供用户下载。但是请注意,选择可靠的、信誉良好的网站进行下载,以避免下载到未经过安全检查或篡改过的镜像文件。 无论使用哪种方式,下载完成后可以使用相关工具进行验证、安装和升级操作系统。同时,为了保证计算机安全,建议从官方和可靠渠道下载操作系统镜像,确保安装前备份重要数据,以免因安装过程中数据丢失造成不必要的麻烦。 ### 回答2: 对于Big Sur 11.2.3镜像的下载,可以通过以下步骤进行: 1. 打开你的网络浏览器,例如Chrome、Safari等。 2. 在搜索引擎中搜索“Big Sur 11.2.3镜像下载”。你将看到一系列的搜索结果,其中包括了可能能提供下载链接的网站。 3. 点击其中一个可靠的网站链接,如苹果官方网站或其他可信的软件下载网站。 4. 在网站上找到相关的下载页面或链接。有些网站可能会直接提供下载链接,而其他网站则需要你点击进入特定的页面后再进行下载。 5. 点击下载链接,开始下载Big Sur 11.2.3镜像文件。镜像文件可能是一个较大的文件,所以需要耐心等待下载完成。 注意事项: - 确保从可靠和正规的网站下载,以避免下载到恶意软件或病毒。 - 查看下载链接是否与你所使用的操作系统相匹配。例如,确保下载的镜像适用于Mac系统。 - 在下载过程中,确保你的网络连接稳定,以免下载中断或出现错误。 一旦下载完成,你就可以根据需要将Big Sur 11.2.3镜像文件用于安装、更新或其他用途了。记得在使用镜像文件前备份重要数据,按照相关指南或教程进行操作。 ### 回答3: Big Sur 11.2.3是苹果公司最新发布的操作系统版本。想要下载Big Sur 11.2.3的镜像文件可以通过以下步骤进行。 首先,打开苹果官方网站。在官方网站上,你可以找到下载Big Sur 11.2.3镜像文件的链接。点击链接后,你将被引导到一个新的页面或下载选项。 其次,选择合适的下载选项。通常,苹果官方网站会提供多个下载选项,包括安装器和镜像文件。如果想要下载Big Sur 11.2.3的镜像文件,可以选择与镜像相关的选项或链接。 接下来,等待镜像文件下载完成。镜像文件的下载速度取决于网络状况和文件大小。请耐心等待下载完成,确保镜像文件完整下载。 完成下载后,你就拥有了Big Sur 11.2.3的镜像文件。你可以将其保存在你的电脑或其他存储设备上,以备日后使用。在安装操作系统或升级现有系统时,你可以使用这个镜像文件来进行安装或升级。 需要注意的是,下载Big Sur 11.2.3镜像文件需要保持网络畅通,且确认文件来源可信。同时,确保你的设备满足Big Sur 11.2.3的系统要求,以获得更好的使用体验。 希望以上回答对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值