Gig*_*igi 13 c sockets linux port multicast
我有一个应用程序从同一端口上的多个组播源接收数据.我能够收到数据.但是,我试图考虑每个组的统计信息(即收到的消息,收到的字节数),所有数据都混淆了.有谁知道如何解决这个问题?如果我试着查看发件人的地址,那么它不是多播地址,而是发送机器的IP.
我使用以下套接字选项:
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("224.1.2.3");
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
Run Code Online (Sandbox Code Playgroud)
并且:
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
Run Code Online (Sandbox Code Playgroud)
DS.*_*DS. 10
[编辑澄清bind()实际上可能包含多播地址.]
因此,应用程序正在连接多个多播组,并将发送到其中任何一个的消息接收到同一端口.SO_REUSEPORT允许您将多个套接字绑定到同一个端口.除端口外,还bind()需要一个IP地址.INADDR_ANY是一个包罗万象的地址,但也可以使用IP地址,包括多播地址.在这种情况下,只有发送到该IP的数据包才会被传送到套接字.即,您可以创建多个套接字,每个多播组一个.bind()每个套接字到(group_addr,port),AND join group_addr.然后,发往不同组的数据将显示在不同的套接字上,您将能够以这种方式区分它.
我测试了以下适用于FreeBSD:
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
const char *group = argv[1];
int s = socket(AF_INET, SOCK_DGRAM, 0);
int reuse = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
fprintf(stderr, "setsockopt: %d\n", errno);
return 1;
}
/* construct a multicast address structure */
struct sockaddr_in mc_addr;
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = inet_addr(group);
mc_addr.sin_port = htons(19283);
if (bind(s, (struct sockaddr*) &mc_addr, sizeof(mc_addr)) == -1) {
fprintf(stderr, "bind: %d\n", errno);
return 1;
}
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = INADDR_ANY;
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
char buf[1024];
int n = 0;
while ((n = read(s, buf, 1024)) > 0) {
printf("group %s fd %d len %d: %.*s\n", group, s, n, n, buf);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您针对不同的多播地址运行多个此类进程,并向其中一个地址发送消息,则只有相关进程才会收到该进程.当然,你的情况,你可能会想将所有的插座在一个过程中,你将不得不使用select或poll或等同于阅读所有.
mpr*_*net 10
经过几年面对这个linux奇怪的行为,并使用前面的答案中描述的绑定解决方法,我意识到ip(7)联机帮助页描述了一个可能的解决方案:
IP_MULTICAST_ALL(自Linux 2.6.31起)
此选项可用于修改组播消息到绑定到通配符INADDR_ANY地址的套接字的传递策略.参数是一个布尔整数(默认为1).如果设置为1,则套接字将从整个系统上全局加入的所有组接收消息.否则,它将仅从已在此特定套接字上显式连接的组(例如,通过IP_ADD_MEMBERSHIP选项)传递消息.
然后,您可以使用以下命令激活过滤器以接收已连接组的消息:
int mc_all = 0;
if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) {
perror("setsockopt() failed");
}
Run Code Online (Sandbox Code Playgroud)
在Redhat Bug 231899中讨论了这个问题以及解决它的方法来启用IP_MULTICAST_ALL ,这个讨论包含重现问题并解决它的测试程序.
假设使用setsockopt()和/ IP_PKTINFO或IP_RECVDSTADDR取决于您的平台.结合recvmsg()或WSARecvMsg()允许您查找每个数据包的源和目标地址.
Unix/Linux,注意FreeBSD使用IP_RECVDSTADDR虽然都支持IP6_PKTINFOIPv6.
Windows,也有 IP_ORIGINAL_ARRIVAL_IF
| 归档时间: |
|
| 查看次数: |
17109 次 |
| 最近记录: |