简体   繁体   English

无法通过多个“读取”调用从多播套接字读取 RTP 数据包(或获取其大小)

[英]Can't read RTP packet (or get its size) from multicast socket via several 'read' calls

I have trouble reading RTP packets from a multicast socket which is opened using the following function:我无法从使用以下函数打开的多播套接字读取 RTP 数据包:

int
    open_multicast_socket
        (const char *group_address,
         uint16_t port)
{
    assert(group_address != NULL);

    int
        s;

    if (-1 != (s = socket(
        AF_INET, SOCK_DGRAM, 0
    )))
    {
        int
            reuse = 1;

        if (-1 != setsockopt(
            s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse
        ))
        {
            struct sockaddr_in
                sock_addr;

            bzero(&sock_addr, sizeof sock_addr);

            if (1 == inet_pton(
                AF_INET, group_address, &sock_addr.sin_addr
            ))
            {
                sock_addr.sin_family      = AF_INET;
                sock_addr.sin_port        = htons(port);

                if (0 == bind(
                    s, (struct sockaddr*)&sock_addr, sizeof sock_addr
                ))
                {
                    struct ip_mreq
                        mreq = {
                            .imr_multiaddr.s_addr = inet_addr(group_address),
                            .imr_interface.s_addr = htonl(INADDR_ANY)
                        };

                    if (0 == setsockopt(
                        s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof mreq
                    ))
                    {
                        //fcntl(s, F_SETFL, O_NONBLOCK);
                        return s;
                    } // setsockopt
                    else
                    {
                        perror("setsockopt");
                        close(s);
                    }
                } // bind
                else
                {
                    perror("bind");
                    close(s);
                }
            } // inet_pton
            else
            {
                perror("inet_pton");
                close(s);
            }
        } // setsockopt
        else
        {
            perror("setsockopt");
            close(s);
        }
    } // socket
    else
    {
        perror("socket");
    }

    return -1;
}

If I read RTP header plus payload in one read operation, I get the entire packet.如果我在一次read操作中读取 RTP 标头和有效负载,我会得到整个数据包。 However, if I attempt to receive the RTP header first, then - a custom header in the payload - the 2nd read always gets a next RTP header instead, discarding all attached data.但是,如果我首先尝试接收 RTP 标头,那么 - 有效负载中的自定义标头 - 第二次read总是会获得下一个 RTP 标头,而丢弃所有附加数据。 Because payload length may vary, the only way to receive a whole packet, it seems, is to guess its max possible size.由于有效载荷长度可能会有所不同,因此接收整个数据包的唯一方法似乎是猜测其最大可能大小。

I tried to get a number of available bytes before reading:在阅读之前,我尝试获取一些可用字节:

ioctl(sock, FIONREAD, &nbytes);

but it always returns 0.但它总是返回 0。

Polling on the socket always fails, as if no data is available at all.对套接字的轮询总是失败,就好像根本没有可用的数据一样。

When non-blocking is enabled (ie fcntl(sock, F_SETFL, O_NONBLOCK); ) - read always fails (-1), so does recv(sock, buf, buf_len, MSG_DONTWAIT) .当启用非阻塞时(即fcntl(sock, F_SETFL, O_NONBLOCK); ) - read总是失败 (-1), recv(sock, buf, buf_len, MSG_DONTWAIT)

So is there a way to properly parse RTP packets via consequensive non-blocking read calls?那么有没有办法通过相应的非阻塞read调用正确解析 RTP 数据包?

Non-blocking is essential, because it should be possible to check whether a connection was lost and re-open the socket if necessary.非阻塞是必不可少的,因为应该可以检查连接是否丢失并在必要时重新打开套接字。

Unlike TCP which is a stream based protocol, UDP is a packet based protocol.与 TCP 是基于流的协议不同,UDP 是基于数据包的协议。 This means that whenever you read from a UDP socket (multicast or not) you'll get exactly one UDP datagram.这意味着无论何时您从 UDP 套接字(多播与否)读取数据,您都会得到一个 UDP 数据报。 If your buffer isn't big enough to hold the entire datagram, the remaining data is essentially lost.如果您的缓冲区不足以容纳整个数据报,则剩余的数据基本上会丢失。

Make sure your buffer is big enough to hold a complete datagram.确保您的缓冲区足够大以容纳完整的数据报。 If your network supports jumbo frames end-to-end that means your buffer should be 9000 bytes, otherwise it should be 1500 bytes.如果您的网络支持端到端巨型帧,则意味着您的缓冲区应为 9000 字节,否则应为 1500 字节。

One should read the complete buffer from the socket and then parse them.应该从套接字读取完整的缓冲区,然后解析它们。

One can create a buffer of MTU size, read from the socket to this temp buffer and then parser the complete buffer and then take action.可以创建一个 MTU 大小的缓冲区,从套接字读取到这个临时缓冲区,然后解析完整的缓冲区,然后采取行动。

One can use select() or poll() to check if the data is present in the socket.可以使用 select() 或 poll() 来检查数据是否存在于套接字中。 Read it when it is available.当它可用时阅读它。

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

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