一个多播的问题,是否可以指定特定的数据接收的接口?

doubleword 2007-06-20 04:27:12
环境如下:

两台机器a,b,分别有两个网卡,网段分别为10.10.10.0和10.10.20.0
a的地址为10.10.10.1 10.10.20.1
b的地址为10.10.10.2 10.10.20.2
一个任意的多播组224.0.0.101

a接收数据,b发送数据(a,b都为一个进程中处理)。

udp能够在相同的端口号,不同的接口上启动监听。如下:
10.10.10.1:9999
10.10.20.1:9999
0.0.0.0:9999

我如何能够在多播中做到相同的效果呢,让不同的网段的数据通过不同的socket来处理?

我碰到的问题:
当绑定到不同的本地地址的时候,居然接收不到多播数据,很怪异。
...全文
253 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
doubleword 2007-06-21
  • 打赏
  • 举报
回复
用了一个比较无耻的方法。我在绑定本地ip的时候不使用本地接口的地址,而是使用多播地址进行绑定,
这个时候就可以达到我需要的效果了。

struct sockaddr_in addr;

bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
inet_aton(mcastaddr, &addr.sin_addr); // mcastaddr是出传入的多播地址.
addr.sin_port = htonl(PORT);
bind(sockfd, (struct sockaddr *)&addr;
doubleword 2007-06-21
  • 打赏
  • 举报
回复
还是有问题,昨天没太仔细看,原来收到数据包的都还是一个socket,而不是我想要的那种。
看来只能将另外一个socket加到另一个多播组里了。
看来还要对多播的协议好好研究一下。
dai_weitao 2007-06-20
  • 打赏
  • 举报
回复
自己动手最伟大.
doubleword 2007-06-20
  • 打赏
  • 举报
回复
已经解决。
发现设置多播的时候自己犯了个错误,不过不知道为什么。
设置bind的时候绑定的地址使用any就没有问题了,而不使用接口的地址。

其实可以不用struct ip_mreqn这个结构,在监听的时候使用struct ip_mreq就可以了,他们的唯一
区别也就是多了一个ipm_ifindex。
doubleword 2007-06-20
  • 打赏
  • 举报
回复
client:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

#define MULTI_IP "224.0.0.100"
#define MULTI_PORT 4488

int main(int argc,char *argv[])
{
int sockfd;
char buf[] = "hello world\n";
struct ip_mreqn mreqn;
struct sockaddr_in addr;
const uint8_t ttl = 4;
int ret;

if (argc < 2){
printf("%s interface\n",argv[0]);
return 1;
}

sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0){
return -1;
}

memset(&mreqn,0,sizeof(mreqn));
mreqn.imr_address.s_addr = htonl(INADDR_ANY);
mreqn.imr_ifindex = if_nametoindex(argv[1]);
if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &mreqn,sizeof(mreqn)) != 0){
perror("IP_MULTICAST_IF");
}
if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(int)) != 0){
perror("TTL");
}

ret = 0;
if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &ret, sizeof(int)) != 0){
perror("LOOP");
}

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(MULTI_IP);
addr.sin_port = htons(MULTI_PORT);
if (sendto(sockfd, buf, strlen(buf), 0,
(struct sockaddr*)&addr, sizeof(addr)) != strlen(buf)){
perror("sendto");
}
close(sockfd);
return 0;
}

doubleword 2007-06-20
  • 打赏
  • 举报
回复
server:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <net/if.h>

#define MULTICAST "224.0.0.100"
#define PORT 4488
#define MAX(a,b) ((a)>(b)?(a):(b))

int before_recv(const char *nic_name, int sockfd, const char *localip, uint16_t port, const char *mcastip)
{
struct sockaddr_in addr;
struct ip_mreqn ipm;
int reuse = 1;
uint8_t loop = 1;

assert(NULL != mcastip);

/* set multicast */
bzero(&ipm, sizeof(ipm));
/* set local ip */
if (NULL == localip) {
ipm.imr_address.s_addr = htonl(INADDR_ANY);
}
else {
if (inet_aton(localip, &ipm.imr_address) == 0) {
perror("inet_aton localip");
return -1;
}
}
if (inet_aton(mcastip, &ipm.imr_multiaddr) == 0) {
perror("inet_aton mcastip");
return -1;
}
ipm.imr_ifindex = if_nametoindex(nic_name);
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipm, sizeof(ipm)) < 0) {
perror("setsocketopt mcast");
return -1;
}

if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) {
perror("setsockopt loop");
return -1;
}

/* set reuse */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
perror("setsockopt reuse");
return -1;
}
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
if (NULL == localip) {
addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else {
if (inet_aton(localip, &addr.sin_addr) == 0) {
perror("inet_aton localip for address");
return -1;
}
}
addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return -1;
}

return 0;
}

int main(int argc, char **argv)
{
int sockfd1 = 0;
int sockfd2 = 0;
int maxfd = 0;
fd_set fdr;

if ((sockfd1 = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return -1;
}
if (before_recv("eth0", sockfd1, "10.10.51.2", PORT, MULTICAST) < 0) {
return -1;
}
maxfd = MAX(sockfd1, maxfd);

if ((sockfd2 = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket");
return -1;
}
if (before_recv("eth1", sockfd2, "193.168.20.104", PORT, MULTICAST) < 0) {
return -1;
}
maxfd = MAX(sockfd2, maxfd);

FD_ZERO(&fdr);
while (1) {
char buf[512];
struct sockaddr_in addr;
socklen_t len;
ssize_t n;

FD_SET(sockfd1, &fdr);
FD_SET(sockfd2, &fdr);

if (select(maxfd + 1, &fdr, NULL, NULL, NULL) < 0) {
if (EINTR == errno) {
continue;
}
else {
perror("select");
}
}
if (FD_ISSET(sockfd1, &fdr)) {
len = sizeof(addr);
if ((n = recvfrom(sockfd1, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &len)) < 0) {
perror("read sockfd1 error");
}
printf("%d\n", n);
buf[n] = '\0';
fprintf(stderr, "sockfd1 recv ip [%s] content [%s]\n",
inet_ntoa(addr.sin_addr), buf);
}
if (FD_ISSET(sockfd2, &fdr)) {
len = sizeof(addr);
if ((n = recvfrom(sockfd2, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &len)) < 0) {
perror("read sockfd1 error");
}
buf[n] = '\0';
fprintf(stderr, "sockfd2 recv ip [%s] content [%s]\n",
inet_ntoa(addr.sin_addr), buf);

}
}
return 0;
}

23,110

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧