linux 下进程之间通讯的几种方式,管道,有名管道,信号量,共享内存,信号,消息队列,套接字,网上都是很多例子的,现在想用多播的方式在同一台主机下的几个进程直接通信,不知道可不可行?
写了一个发送和接收组播的小例子来测试,代码如下:
mcast_send.c
-
#include<stdio.h>
-
#include<stdlib.h>
-
#include<string.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <linux/in.h>
-
-
#define MCAST_PORT 8888
-
#define MCAST_ADDR "224.0.0.100" /*多播组地址*/
-
#define MCAST_DATA "BROADCAST TEST DATA" /*多播发送的数据*/
-
#define MCAST_INTERVAL 5 /*发送间隔时间*/
-
#define MCAST_SEND_ADDR "192.168.7.201" /*发送的出接口的ip地址*/
-
-
int main(int argc, char*argv)
-
{
-
int s;
-
struct sockaddr_in mcast_addr;
-
int err = -1;
-
-
s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
-
if (s == -1)
-
{
-
perror("socket()");
-
return -1;
-
}
-
-
memset(&mcast_addr, 0, sizeof(mcast_addr));
-
mcast_addr.sin_family = AF_INET;
-
mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);/*设置多播IP地址*/
-
mcast_addr.sin_port = htons(MCAST_PORT); /*设置多播端口*/
-
-
struct in_addr out_if;
-
out_if.s_addr = inet_addr(MCAST_SEND_ADDR);
-
err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_IF,&out_if, sizeof(out_if)); /*设置多播发送的出接口*/
-
if(err < 0){
-
perror("setsockopt():IP_MULTICAST_IF");
-
return -1;
-
}
-
-
unsigned char loop = 1;
-
err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_LOOP,&loop, sizeof(loop)); /*设置数据包是否回送loopback口,0 不回送,1 回送*/
-
if(err < 0){
-
perror("setsockopt():IP_MULTICAST_LOOP");
-
return -1;
-
}
-
-
unsigned char ttl = 64;
-
err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_TTL,&ttl, sizeof(ttl)); /*设置数据包的ttl*/
-
if(err < 0){
-
perror("setsockopt():IP_MULTICAST_TTL");
-
return -1;
-
}
-
/*向多播地址发送数据*/
-
while(1) {
-
int n = sendto(s, /*套接字描述符*/
-
MCAST_DATA, /*数据*/
-
sizeof(MCAST_DATA), /*长度*/
-
0,
-
(struct sockaddr*)&mcast_addr,
-
sizeof(mcast_addr)) ;
-
if( n < 0)
-
{
-
perror("sendto()");
-
return -1;
-
}
-
-
sleep(MCAST_INTERVAL); /*每隔5秒发送一次*/
-
}
-
-
return 0;
-
}
mcast_recv.c
-
#include<stdio.h>
-
#include<stdlib.h>
-
#include<string.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <linux/in.h>
-
-
#define MCAST_PORT 8888
-
#define MCAST_ADDR "224.0.0.100" /*多播地址组地址*/
-
#define MCAST_INTERVAL 5 /*发送间隔时间*/
-
#define MCAST_RECV_ADDR "192.168.7.201" /*加入多播组所在接口的IP*/
-
#define BUFF_SIZE 256 /*接收缓冲区大小*/
-
-
int main(int argc, char*argv[])
-
{
-
int s;
-
struct sockaddr_in local_addr; /*本地地址*/
-
int err = -1;
-
-
s = socket(AF_INET, SOCK_DGRAM, 0); /*建立套接字*/
-
if (s == -1)
-
{
-
perror("socket()");
-
return -1;
-
}
-
-
-
memset(&local_addr, 0, sizeof(local_addr));
-
local_addr.sin_family = AF_INET;
-
local_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);
-
local_addr.sin_port = htons(MCAST_PORT);
-
-
int reuse = 1;
-
err = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); /*允许本地ip地址重用,可以多个进程同时进行绑定接收*/
-
if(err < 0){
-
perror("setsocketopt SO_REUSEADDR");
-
return -2;
-
}
-
-
err = bind(s,(struct sockaddr*)&local_addr, sizeof(local_addr)) ; /*本地绑定了组播组的ip,才会接收到目的ip为组播组ip的数据包*/
-
if(err < 0)
-
{
-
perror("bind()");
-
return -2;
-
}
-
-
-
-
-
struct ip_mreq mreq;
-
mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR); /*多播组IP地址*/
-
mreq.imr_interface.s_addr = inet_addr(MCAST_RECV_ADDR); /*加入多播组的接口*/
-
-
err = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)); /*将本接口加入多播组*/
-
if (err < 0)
-
{
-
perror("setsockopt():IP_ADD_MEMBERSHIP");
-
return -4;
-
}
-
-
int times = 0;
-
int addr_len = 0;
-
char buff[BUFF_SIZE];
-
int n = 0;
-
-
for(times = 0;times<100;times++){ /*循环接收多播组的消息,100次后退出*/
-
addr_len = sizeof(local_addr);
-
memset(buff, 0, BUFF_SIZE); /*清空接收缓冲区*/
-
-
n = recvfrom(s, buff, BUFF_SIZE, 0,(struct sockaddr*)&local_addr,&addr_len);/*接收数据*/
-
if( n== -1){
-
perror("recvfrom()");
-
}
-
-
printf("Recv %dst message from server:%s\n", times, buff); /*打印接收到的信息*/
-
sleep(MCAST_INTERVAL);
-
}
-
-
err = setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));/*退出多播组*/
-
-
close(s);
-
return 0;
-
}
通过上面的两个小程序在同一台主机上进行测试,得到如下的结果:
说明:
接收和发送都是在同一台主机上进行
不同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) |