Chinaunix首页 | 论坛 | 博客
  • 博客访问: 234918
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 296
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-22 11:52
文章分类

全部博文(31)

文章存档

2018年(3)

2017年(11)

2016年(12)

2015年(5)

我的朋友

分类: C/C++

2017-08-20 11:42:42

linux 下进程之间通讯的几种方式,管道,有名管道,信号量,共享内存,信号,消息队列,套接字,网上都是很多例子的,现在想用多播的方式在同一台主机下的几个进程直接通信,不知道可不可行?
写了一个发送和接收组播的小例子来测试,代码如下:

mcast_send.c

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <linux/in.h>

  7. #define MCAST_PORT 8888
  8. #define MCAST_ADDR "224.0.0.100"          /*多播组地址*/
  9. #define MCAST_DATA "BROADCAST TEST DATA"  /*多播发送的数据*/
  10. #define MCAST_INTERVAL 5                  /*发送间隔时间*/
  11. #define MCAST_SEND_ADDR "192.168.7.201"    /*发送的出接口的ip地址*/

  12. int main(int argc, char*argv)
  13. {
  14.     int s;
  15.     struct sockaddr_in mcast_addr;
  16.     int err = -1;

  17.     s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
  18.     if (s == -1)
  19.     {
  20.         perror("socket()");
  21.         return -1;
  22.     }
  23.    
  24.     memset(&mcast_addr, 0, sizeof(mcast_addr));
  25.     mcast_addr.sin_family = AF_INET;
  26.     mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);/*设置多播IP地址*/
  27.     mcast_addr.sin_port = htons(MCAST_PORT);           /*设置多播端口*/

  28.     struct in_addr out_if;
  29.     out_if.s_addr = inet_addr(MCAST_SEND_ADDR);  
  30.     err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_IF,&out_if, sizeof(out_if));  /*设置多播发送的出接口*/
  31.     if(err < 0){
  32.         perror("setsockopt():IP_MULTICAST_IF");
  33.         return -1;
  34.     }

  35.     unsigned char loop = 1;
  36.     err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_LOOP,&loop, sizeof(loop));   /*设置数据包是否回送loopback口,0 不回送,1 回送*/
  37.     if(err < 0){
  38.         perror("setsockopt():IP_MULTICAST_LOOP");
  39.         return -1;
  40.     }

  41.     unsigned char ttl = 64;
  42.     err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_TTL,&ttl, sizeof(ttl));     /*设置数据包的ttl*/
  43.     if(err < 0){
  44.         perror("setsockopt():IP_MULTICAST_TTL");
  45.         return -1;
  46.     }
  47.                                             /*向多播地址发送数据*/
  48.     while(1) {
  49.         int n = sendto(s, /*套接字描述符*/
  50.                        MCAST_DATA, /*数据*/
  51.                        sizeof(MCAST_DATA), /*长度*/
  52.                        0,
  53.                        (struct sockaddr*)&mcast_addr,
  54.                        sizeof(mcast_addr)) ;
  55.         if( n < 0)
  56.         {
  57.             perror("sendto()");
  58.             return -1;
  59.         }

  60.         sleep(MCAST_INTERVAL);                 /*每隔5秒发送一次*/
  61.     }

  62.     return 0;
  63. }

mcast_recv.c

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <linux/in.h>

  7. #define MCAST_PORT 8888
  8. #define MCAST_ADDR "224.0.0.100"     /*多播地址组地址*/
  9. #define MCAST_INTERVAL 5             /*发送间隔时间*/
  10. #define MCAST_RECV_ADDR "192.168.7.201"  /*加入多播组所在接口的IP*/
  11. #define BUFF_SIZE 256                  /*接收缓冲区大小*/

  12. int main(int argc, char*argv[])
  13. {
  14.     int s;
  15.     struct sockaddr_in local_addr; /*本地地址*/
  16.     int err = -1;
  17.    
  18.     s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
  19.     if (s == -1)
  20.     {
  21.         perror("socket()");
  22.         return -1;
  23.     }
  24.    
  25.                                                 
  26.     memset(&local_addr, 0, sizeof(local_addr));
  27.     local_addr.sin_family = AF_INET;
  28.     local_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);
  29.     local_addr.sin_port = htons(MCAST_PORT);
  30.    
  31.     int reuse = 1;
  32.     err = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); /*允许本地ip地址重用,可以多个进程同时进行绑定接收*/
  33.     if(err < 0){
  34.         perror("setsocketopt SO_REUSEADDR");
  35.         return -2;
  36.     }

  37.     err = bind(s,(struct sockaddr*)&local_addr, sizeof(local_addr)) ; /*本地绑定了组播组的ip,才会接收到目的ip为组播组ip的数据包*/
  38.     if(err < 0)
  39.     {
  40.         perror("bind()");
  41.         return -2;
  42.     }




  43.     struct ip_mreq mreq;                                     
  44.     mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR);       /*多播组IP地址*/
  45.     mreq.imr_interface.s_addr = inet_addr(MCAST_RECV_ADDR);  /*加入多播组的接口*/
  46.                                                            
  47.     err = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq))/*将本接口加入多播组*/
  48.     if (err < 0)
  49.     {
  50.         perror("setsockopt():IP_ADD_MEMBERSHIP");
  51.         return -4;
  52.     }

  53.     int times = 0;
  54.     int addr_len = 0;
  55.     char buff[BUFF_SIZE];
  56.     int n = 0;
  57.                                         
  58.     for(times = 0;times<100;times++){   /*循环接收多播组的消息,100次后退出*/
  59.         addr_len = sizeof(local_addr);
  60.         memset(buff, 0, BUFF_SIZE);                 /*清空接收缓冲区*/
  61.                                                     
  62.         n = recvfrom(s, buff, BUFF_SIZE, 0,(struct sockaddr*)&local_addr,&addr_len);/*接收数据*/
  63.         if( n== -1){
  64.             perror("recvfrom()");
  65.         }
  66.                                                     
  67.         printf("Recv %dst message from server:%s\n", times, buff)/*打印接收到的信息*/
  68.         sleep(MCAST_INTERVAL);
  69.     }
  70.                                                  
  71.     err = setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));/*退出多播组*/

  72.     close(s);
  73.     return 0;
  74. }

通过上面的两个小程序在同一台主机上进行测试,得到如下的结果:


说明:
接收和发送都是在同一台主机上进行
不同ip是配置在不同接口上的,其中192.168.7.201 是在eth5,192.168.220.201是在eth4,
127.0.0.1 是在loopback口上,loop 为0 表示发送的进程设置了不回送loopback口,为1表示
发送进程设置了回送loopback口

上面的测试,在不同终端,开启了一个发送进程,多个接收进程,其中能接收到的时候,是多个接收进程都接收成功的
通过上面得结果可以看出,通过组播在同一台主机的多个进程间通讯是可行的,最合理的做法应该就是,发送和接收都
通过loopback进行,而loop参考可设置为0或者1 。虽然发送和接收都通过eth5,并且把loop 设置为1 ,接收进程也是能
接收到,但是其他主机的和发送ip在同一个网段的接口也能接收到,这个是我们不希望看到的。为了能让多个进程同时
接收,必须在bind 之前把地址设为可重复使用的。

测试的时候也尝试过不设置发送的出接口,这个时候系统就会根据路由选择默认的接口。

总结:灵活运用setsocketopt 总会带来各种意向不到的效果的。

阅读(2204) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~