2024.12.30(多点通信)

海哥  论坛元老 | 2024-12-31 20:15:35 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1589|帖子 1589|积分 4767

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
作业:
1、将广播发送和吸收端实现一遍,完成一个发送端发送信息,对应多个吸收端吸收信息实验。
发送端
  1. #include <myhead.h>
  2. #define PORT 8888
  3. #define IP "192.168.124.255"
  4. int main(int argc, const char *argv[])
  5. {
  6.         //1、将广播发送和接收端实现一遍,
  7.         //完成一个发送端发送信息,对应多个接收端接收信息实验。
  8.         //1.创建套接字
  9.         int oldfd = socket(AF_INET,SOCK_DGRAM,0);
  10.         if(oldfd == -1)
  11.         {
  12.                 perror("socket");
  13.                 return -1;
  14.         }
  15.         //设置允许广播
  16.         int k = 11;
  17.         if(setsockopt(oldfd,SOL_SOCKET,SO_BROADCAST,&k,sizeof(k))==-1)
  18.         {
  19.                 perror("setsockopt");
  20.                 return -1;
  21.         }
  22.         printf("允许广播设置成功\n");
  23.         struct sockaddr_in broadcast = {
  24.                 .sin_family = AF_INET,
  25.                 .sin_port = htons(PORT),         //发送到该端口
  26.                 .sin_addr.s_addr = inet_addr(IP)
  27.         };
  28.         char buff[1024];
  29.         while(1)
  30.         {
  31.                 fgets(buff,sizeof(buff),stdin);
  32.                 sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&broadcast,sizeof(broadcast));
  33.                 if(strcmp(buff,"quit")==0)
  34.                 {
  35.                         printf("发送端退出\n");
  36.                         break;
  37.                 }
  38.         }
  39.         close(oldfd);
  40.         return 0;
  41. }
复制代码
吸收端
  1. #include <myhead.h>
  2. #define PORT 8888
  3. #define IP "192.168.124.255"
  4. int main(int argc, const char *argv[])
  5. {
  6.         //1.创建套接字
  7.         int oldfd = socket(AF_INET,SOCK_DGRAM,0);
  8.         if(oldfd == -1)
  9.         {
  10.                 perror("socket");
  11.                 return -1;
  12.         }
  13.         //填充广播地址信息结构体
  14.         struct sockaddr_in send = {
  15.                 .sin_family = AF_INET,
  16.                 .sin_port = htons(PORT),
  17.                 .sin_addr.s_addr = inet_addr(IP)
  18.         };
  19.         if(bind(oldfd,(struct sockaddr *)&send,sizeof(send))==-1)
  20.         {
  21.                 perror("bind");
  22.                 return -1;
  23.         }
  24.         //接收消息
  25.         char buff[1024];
  26.         while(1)
  27.         {
  28.                 recvfrom(oldfd,buff,sizeof(buff),0,NULL,NULL);
  29.                 printf("%s",buff);
  30.         }
  31.         return 0;
  32. }
复制代码
2、利用多线程基于TCP协议的并发执行,一个服务器对应多个客户端实现通信实验。
服务器
  1. #include <myhead.h>
  2. #define PORT 8888
  3. #define IP "192.168.124.123"
  4. void *fun(void *fd)
  5. {
  6.         int newfd = *(int *)fd;
  7.         char buff[1024];
  8.         while(1)
  9.         {
  10.                 int res = recv(newfd,buff,sizeof(buff),0);
  11.                 if(res == 0)
  12.                 {
  13.                         printf("客户端下线\n");
  14.                         break;
  15.                 }
  16.                 strcat(buff,"霜之哀伤");
  17.                 printf("%s\n",buff);
  18.                 send(newfd,buff,sizeof(buff),0);
  19.                 bzero(buff,sizeof(buff));
  20.         }
  21.         //循环结束(客户端下线)子线程退出
  22.         pthread_exit(NULL);
  23. }
  24. int main(int argc, const char *argv[])
  25. {
  26.         //2、使用多线程基于TCP协议的并发执行,
  27.        
  28.         //一个服务器对应多个客户端实现通信实验。
  29.        
  30.         //1.创建套接字
  31.         int oldfd = socket(AF_INET,SOCK_STREAM,0);
  32.         if(oldfd == -1)
  33.         {
  34.                 perror("socket");
  35.                 return -1;
  36.         }
  37.         //绑定
  38.         struct sockaddr_in aaa = {
  39.                 .sin_family = AF_INET,
  40.                 .sin_port = htons(PORT),
  41.                 .sin_addr.s_addr = inet_addr(IP)
  42.         };
  43.         if(bind(oldfd,(struct sockaddr *)&aaa,sizeof(aaa))==-1)
  44.         {
  45.                 perror("bind");
  46.                 return -1;
  47.         }
  48.         //监听
  49.         if(listen(oldfd,20)==-1)
  50.                 {
  51.                         perror("listen");
  52.                         return -1;
  53.                 }
  54.         struct sockaddr_in client;
  55.         int client_len = sizeof(client);
  56.         pthread_t tid;
  57.         int newfd;
  58.         while(1)
  59.         {
  60.                 //接收新客户端连入请求
  61.                 newfd = accept(oldfd,(struct sockaddr *)&client,&client_len);
  62.                 if(newfd == -1)
  63.                 {
  64.                         perror("accept");
  65.                         return -1;
  66.                 }
  67.                 //创建子线程与客户端通话
  68.                 if(pthread_create(&tid,NULL,fun,&newfd)==-1)
  69.                 {
  70.                         perror("pthread_create");
  71.                         return -1;
  72.                 }
  73.         }
  74.         pthread_join(tid,NULL);         //回收子线程资源
  75.         close(newfd);
  76.         close(oldfd);
  77.        
  78.         return 0;
  79. }
复制代码
客户端
  1. #include <myhead.h>
  2. #define IP "192.168.124.123"
  3. #define PORT 8888
  4. int main(int argc, const char *argv[])
  5. {
  6.         //1.创建套接字
  7.         int oldfd = socket(AF_INET,SOCK_STREAM,0);
  8.         if(oldfd == -1)
  9.         {
  10.                 perror("socket");
  11.                 return -1;
  12.         }
  13.         //连接服务器
  14.         struct sockaddr_in aaa = {
  15.                 .sin_family = AF_INET,
  16.                 .sin_port = htons(PORT),
  17.                 .sin_addr.s_addr = inet_addr(IP)
  18.         };
  19.         if(connect(oldfd,(struct sockaddr *)&aaa,sizeof(aaa))==-1)
  20.         {
  21.                 perror("connect");
  22.                 return -1;
  23.         }
  24.         //收发消息
  25.         char buff[1024];
  26.         while(1)
  27.         {
  28.                 fgets(buff,sizeof(buff),stdin);
  29.                 buff[strlen(buff)-1] = '\0';
  30.                 send(oldfd,buff,strlen(buff),0);
  31.                 if(strcmp(buff,"quit")==-1)
  32.                 {
  33.                         printf("服务器退出成功\n");
  34.                 }
  35.                 bzero(buff,sizeof(buff));
  36.                 recv(oldfd,buff,strlen(buff),0);                 //阻塞接收服务器消息
  37.                 printf("服务器发来消息:%s\n",buff);
  38.         }
  39.         return 0;
  40. }
复制代码
笔记

1、对于套接字而言,在不同的层中,可以设置不同的属性,如端标语快速重用、超时时间、设置广播、加入多播组等等
2、关于网络属性,有两个函数,分别是 setsockopt、getsockopt

           #include <sys/types.h> /* See NOTES */
          #include <sys/socket.h>
          int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
          功能:获取套接字某些选项的属性。
          参数1:套接字描述符
          参数2:要获取的层级
          参数3:要获取的操作名称
          参数4:获取的值为         0:表示禁用,
                                                  非0表示启用。
          参数5:参数4的巨细。
          返回值:乐成返回0,失败返回-1,并置位错误码
          int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
          功能:设置套接字某些选项的属性。
          参数1:套接字描述符
          参数2:要设置的层级
          参数3:要设置的操作名称
          参数4:设置的值, 0:表示禁用,
                                          非0表示启用。
          参数5:参数4的巨细。
          返回值:乐成返回0,失败返回-1,并置位错误码
  eg:获取当前端标语是否能快速复用属性:
          int n;
          int len = sizeof(n);
          getsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&n,&len);
          如果n==0表示端标语快速复用未启动。
          如果n!=0表示端标语快速复用启动。
          eg:设置当前套接字端标语能快速复用
          int n =999;
          setsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(n));
          启动端标语快速复勤奋能。
  1. #include <myhead.h>
  2. int main(int argc, const char *argv[])
  3. {
  4.     int oldfd = socket(AF_INET,SOCK_STREAM,0);
  5.     int n;
  6.     int len = sizeof(n);
  7.     getsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&n,&len);
  8.     printf("端口号复用状态:%d\n",n);
  9.    
  10. n = 1;
  11.     setsockopt(oldfd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(n));
  12.     printf("端口号修改为可复用状态后:%d\n",n);
  13.     return 0;
  14. }
复制代码
2.单播
1>.单播发生在主机之间一对一的通信模式,交换机大概路由器只对数据举行转发,不做复制
2> 每次只有两个实体之间举行相互通信,发送端和吸收端都是唯一确定的
3.广播
1>主机之间的一对多的通信模式,网络对此中的每一台主机发出的信息都举行复制并转发
2>全部主机都可以收到广播消息(无论你是否乐意吸收),所以,广播是基于UDP通信模式
3> 广播地址:网络号 + 255
比方:主机地址为192.168.125.171 ---> 192.168.125.255
4> 广播消息是不能穿过路由器的,也就是说广播消息禁止在外网上举行传播,所以广播只能完成局域网内的多点通信
1、广播的发送端模子 ----> 类似于UDP的客户端
   模式
  1> socket 创建套接字
  2> setsockopt 设置网络属性,允许广播
  3> bind 非必须绑定(绑定的话每次发送端口都是固定的)
  4> 填广播地址信息结构体
  ip:填广播地址(192.168.125.255)
  port:与吸收端保持同等
  5> sendto 发送消息
  6> close 关闭套接字
  1. #include <myhead.h>
  2. #define PORT 6666
  3. #define IP "192.168.124.255"
  4. int main(int argc, const char *argv[])
  5. {
  6.     //1、创建套接字
  7.     int oldfd = socket(AF_INET,SOCK_DGRAM,0);
  8.     if(oldfd==-1)
  9.     {
  10.         perror("socket");
  11.         return -1;
  12.     }
  13.     //2、设置允许广播
  14.     int k = 999;
  15.     if(setsockopt(oldfd,SOL_SOCKET,SO_BROADCAST,&k,sizeof(k))==-1)
  16.     {
  17.         perror("setsockopt");
  18.         return -1;
  19.     }
  20.     printf("允许广播设置成功\n");
  21.    
  22.     struct sockaddr_in broadcast = {
  23.         .sin_family = AF_INET,
  24.         .sin_port = htons(PORT),//发送到该端口
  25.         .sin_addr.s_addr = inet_addr(IP)
  26.     };
  27.         
  28.     char buff[1024];
  29.     while(1)
  30.     {
  31.         fgets(buff,sizeof(buff),stdin);
  32.         sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&broadcast,sizeof(broadcast));
  33.         if(strcmp(buff,"quit")==0)
  34.         {
  35.             printf("发送端退出\n");
  36.             break;
  37.         }
  38.     }
  39.     close(oldfd);
  40.     return 0;
  41. }
复制代码
2、广播的吸收端模子 ----> 类似于UDP的服务器端
   模式
  1> socket 创建套接字
  2> 填充地址信息结构体
  ip:广播地址(192.168.125.255)
  port:与发送端保持同等
  3> bind 绑定端标语与ip地址
  4> recvfrom 吸收消息
  5> close 关闭套接字
  发送源的负担:广播 > 组播 > 单播
  特点:
  1、广播地址选取broadcast对应的IP
  2、端标语固定
  3、发送端不需要绑定固定的IP和端标语,只需要向固定的IP和端标语(广播地址)发送信息即可,
  不需要关注谁来吸收。
  4、吸收端必须绑定IP和端标语(广播地址)
  5、如果发送端绑定了IP和端标语之后,吸收端就无法再次绑定,也无法吸收信息。
  4、组播(多播)
1、 组播也是实现主机之间一对多的通信模子,跟广播不同的是,组播发送的消息,只有加入多播组的成员才气收到,没有加入的就无法收到,不会占用柜台的网络带宽。
   
  2> 组播也是利用UDP实现。
  3> 组播地址:就是D类网络,224.0.0.0 -- 239.255.255.255
  2、 组播的发送端模子 --->类似于UDP的客户端
   模式
  1> socket 创建套接字
  2> bind 非必须绑定
  3> 填充吸收端地址信息结构体
  ip:组播地址,与吸收端保持同等(224.0.0.0 -- 239.255.255.255)
  port:与吸收端保持同等
  4> sendto 发送组播消息
  5> close 关闭套接字
  组播发送端:
  特点:
  1、发送端发送给组播组IP和端标语。
  2、发送端不需要绑定本身的IP和端标语,只需要发送到组播地址即可。
  1. #include <myhead.h>
  2. #define PORT 6666
  3. #define IP "192.168.124.172"
  4. int main(int argc, const char *argv[])
  5. {
  6.     //1、创建套接字
  7.     int oldfd = socket(AF_INET,SOCK_DGRAM,0);
  8.     if(oldfd==-1)
  9.     {
  10.         perror("socket");
  11.         return -1;
  12.     }
  13. #if 0
  14.     //2、绑定
  15.     struct sockaddr_in send = {
  16.         .sin_family = AF_INET,
  17.         .sin_port = htons(PORT),
  18.         .sin_addr.s_addr = inet_addr(IP)
  19.     };
  20.     if(bind(oldfd,(struct sockaddr *)&send,sizeof(send))==-1)
  21.     {
  22.         perror("bind");
  23.         return -1;
  24.     }
  25. #endif
  26.     //3、发送接收
  27.     struct sockaddr_in group = {
  28.     .sin_family = AF_INET,
  29.     .sin_port = htons(8888),//组播端口号
  30.     .sin_addr.s_addr = inet_addr("224.1.2.3")//组播IP地址
  31.     };
  32.     char buff[1024];
  33.     while(1)
  34.     {
  35.         fgets(buff,sizeof(buff),stdin);
  36.         buff[strlen(buff)-1] = '\0';
  37.         sendto(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&group,sizeof(group));
  38.     }
  39.     return 0;
  40. }
复制代码
3、组播的吸收端模子 ---> 类似于UDP的服务器
   1> socket 创建套接字
  2> setsockopt 设置网络属性(加入多播组)
  设置层级:IPPROTO_IP
  设置属性:IP_ADD_MEMBERSHIP
  struct ip_mreqn {
          struct in_addr imr_multiaddr; /* 组播IP*/
          struct in_addr imr_address; /* 本机IP*/
          int imr_ifindex; /* 网卡索引 */ };
  3> 填充地址信息结构体然后bind
  ip:组播IP,与发送端保持同等
  port :与发送端保持同等
  4> 界说发送方结构体,吸收发送方信息
  5> recvfrom 吸收消息
  6> close 关闭套接字
  特点:
  1、设置允许加入组播组(发送端的IP),设置加入组播组时需要(组播组IP,本身的IP,本身网卡ens33的索引号一样平常都是2)
  2、查找本身网卡的索引号:ip addr show大概ip ad。
  3、绑定时绑定的是组播组IP和发送端IP保持同等。
  4、吸收端也可以选择不吸收发送方信息,recvfron最后两个参数填NULL即可。
  1. #include <myhead.h>
  2. #define ZIP "224.1.2.3"
  3. #define IP "192.168.60.66"
  4. #define PORT 7777
  5. int main(int argc, const char *argv[])
  6. {
  7.     //1、创建基于UDP的套接字
  8.     int oldfd = socket(AF_INET,SOCK_DGRAM,0);
  9.     if(oldfd==-1)
  10.     {
  11.         perror("socket");
  12.         return -1;
  13.     }
  14.    
  15.     //2、设置允许加入组播组
  16.     struct ip_mreqn recv = {
  17.     .imr_multiaddr.s_addr = inet_addr(ZIP),//组播组IP
  18.     .imr_address.s_addr = inet_addr(IP),//本机IP
  19.     .imr_ifindex = 2 //ens33网卡索引号
  20.     };
  21.     if(setsockopt(oldfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&recv,sizeof(recv))==-1)
  22.     {
  23.         perror("setsockopt");
  24.         return -1;
  25.     }
  26.     //3、绑定
  27.     struct sockaddr_in recv2 = {
  28.     .sin_family = AF_INET,
  29.     .sin_port = htons(PORT),
  30.     .sin_addr.s_addr = inet_addr(ZIP)//绑定组播组IP
  31.     };
  32.     if(bind(oldfd,(struct sockaddr *)&recv2,sizeof(recv2))==-1)
  33.     {
  34.         perror("bind");
  35.         return -1;
  36.     }
  37.     //4、接收信息
  38.     struct sockaddr_in send;
  39.     socklen_t send_len = sizeof(send);
  40.     char buff[1024];
  41.     while(1)
  42.     {
  43.         recvfrom(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&send,&send_len);
  44.                 //recvfrom(oldfd,buff,sizeof(buff),0,NULL,NULL);不接收发送方的信息
  45.         printf("接收到%s发送来的信息:%s\n",inet_ntoa(send.sin_addr),buff);
  46.         if(strcmp(buff,"quit")==0)
  47.         {
  48.             printf("接收端也退出\n");
  49.             break;
  50.         }
  51.     }
  52.     close(oldfd);
  53.     return 0;
  54. }
复制代码
思维导图




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表