• 网络通信--广播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 }

    运行结果:

  • 相关阅读:
    记忆力训练今天早上有了点小进步
    刻意练习
    12.12周计划
    12.6周总结
    The Power of Reading Insights
    Storytelling with Data
    nexus私服和快照正式版本etc
    springboot启动流程分析
    容器启动getBean的流程分析
    canal简介
  • 原文地址:https://www.cnblogs.com/kaijia9/p/3400980.html
Copyright © 2020-2023  润新知