繁体   English   中英

使用单个套接字接收单播和多播数据

[英]receive unicast and multicast data using a single socket

我正在开发基于网络的应用程序,其中我想要接收单播和多播数据。 所以我想知道是否可以使用单个套接字接收单播数据和组播数据。 这是我的代码,截至目前我只能接收单播数据,但不能接收多播数据。

void* rec(void* t)
{
    printf("Rec Thread created\n");
    char buf[200];
    struct sockaddr_in soc;
    soc.sin_family=AF_INET;
    soc.sin_addr.s_addr=inet_addr("123.1.2.3");
    soc.sin_port=htons(1234);

    long sock_fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

    bind(sock_fd,(struct sockaddr *)&soc,sizeof(sockaddr_in));

    struct ip_mreq mreq;
    memset(&mreq,0,sizeof(struct ip_mreq));
    mreq.imr_multiaddr.s_addr=inet_addr("235.5.5.5");
    mreq.imr_interface.s_addr=inet_addr("123.1.2.3");

    setsockopt(sock_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) 

    while(true)
    {
        memset(buf,0,sizeof(buf));
        long size=recvfrom(sock_fd,buf,200,0,NULL,NULL);
        if(size>0)
        {
            printf("recvd %s\n",buf);
        }
        else
        {
            perror("Error receving data");
        }
    }
}

int main(int argc,char* argv[])
{
    pthread_create(&pt,NULL,rec,NULL);
    sleep(2);
    char buf[]="Hello World!;
    struct sockaddr_in soc;
    soc.sin_family=AF_INET;
    soc.sin_addr.s_addr=inet_addr("123.1.2.3");
    soc.sin_port=htons(1234);

    long sock_fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

    sendto(sock_fd,buf,sizeof(buf),0,(struct sockaddr *)&soc,sizeof(sockaddr_in));

    struct sockaddr_in msoc;
    msoc.sin_family=AF_INET;
    msoc.sin_addr.s_addr=inet_addr("235.5.5.5");
    msoc.sin_port=htons(1234);

    char mbuf[]="Hi All!";
    sendto(sock_fd,mbuf,sizeof(mbuf),0,(struct sockaddr *)&msoc,sizeof(sockaddr_in));

    return 0;
}

有可能的。 或者至少'有点'可能。

考虑以下代码:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main(void) {
    struct sockaddr_in vSSocket;
    vSSocket.sin_family = AF_INET;
    vSSocket.sin_addr.s_addr = INADDR_ANY;
    vSSocket.sin_port = htons(1234);

    int vSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (vSocket < 0) {
        perror("socket");
        return 1;
    }

    struct ip_mreq vReq;
    vReq.imr_multiaddr.s_addr = inet_addr("235.5.5.5");
    vReq.imr_interface.s_addr = inet_addr("123.1.2.3");
    if (setsockopt(vSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &vReq, sizeof(vReq)) < 0) {
        perror("setsockopt 2");
        return 1;
    }
    if (bind(vSocket, (struct sockaddr *)&vSSocket, sizeof(vSSocket)) == -1) {
        perror("bind");
        return 1;
    }
    ssize_t r;
    char vBuf[256];
    while (1) {
        r = recv(vSocket, vBuf, sizeof(vBuf), 0);
        if (r < 0) {
            perror("recv");
            break;
        }
        if (memcmp(vBuf, "quit", 4) == 0) {
            printf("quit\n");
            break;
        }
        write(1, vBuf, r);
    }
    return 0;
}

诀窍是:将套接字绑定到INADDR_ANY地址。 所以它会监听你机器的每个界面。 此外,具有地址123.1.2.3的接口加入多播组235.5.5.5,因此它将接收该地址的任何数据包。

您可以使用优秀的socat工具测试此解决方案。 要发送到多播地址:

socat STDIO UDP4-DATAGRAM:235.5.5.5:1234

要发送到单播地址:

socat STDIO UDP4-DATAGRAM:123.1.2.3:1234

程序应输出您发送给它的任何内容,并在收到以“退出”开头的数据包后退出。

是的你可以。 nsilent22的前90%。

  • 将套接字绑定到INADDR_ANY
  • 设置IP_ADD_MEMBERSHIP (ipv6: IPV6_JOIN_GROUP
  • 如果需要发送,请设置IP_MULTICAST_IF (ipv6: IPV6_MULTICAST_IF )以设置组播数据包的输出接口。

这会使您获得一个侦听多播组的套接字,但也会接收到该计算机的所有单播流量。 要将其限制为单个界面,您有两个选择:

  • 设置IP_PKTINFO (ipv6: IPV6_RECVPKTINFO ),使用recvmsg接收数据,并根据in_pktinfo结构的ipi_ifindex成员过滤接收的数据( struct in6_pktinfo ipv6: ipi6_ifindex成员)。
  • 设置(linux特定的)套接字选项SO_BINDTODEVICE (需要root权限)

通过这种方式,您可以获得一个套接字,该套接字从选定的多播组接收多播流量,以及所有单播流量,但仅限于单个接口。

来源:ip,ipv6和socket的联机帮助页。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM