[编辑澄清bind()
实际上可能包括多播地址。]
所以应用程序加入了几个多播组,并接收发送到其中任何一个的消息到同一个端口。SO_REUSEPORT
允许您将多个套接字绑定到同一个端口。除了端口,还bind()
需要一个IP地址。INADDR_ANY
是一个包罗万象的地址,但也可以使用 IP 地址,包括多播地址。在这种情况下,只有发送到该 IP 的数据包才会被传递到套接字。即,您可以创建多个套接字,每个多播组一个。bind()
每个套接字到(group_addr,端口),并加入 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);
}
}
如果您针对不同的多播地址运行多个此类进程,并向其中一个地址发送消息,则只有相关进程会收到它。当然,在您的情况下,您可能希望在一个进程中拥有所有套接字,并且您必须使用select
orpoll
或等效项才能全部读取它们。