[英]Can't read RTP packet (or get its size) from multicast socket via several 'read' calls
我无法从使用以下函数打开的多播套接字读取 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;
}
如果我在一次read
操作中读取 RTP 标头和有效负载,我会得到整个数据包。 但是,如果我首先尝试接收 RTP 标头,那么 - 有效负载中的自定义标头 - 第二次read
总是会获得下一个 RTP 标头,而丢弃所有附加数据。 由于有效载荷长度可能会有所不同,因此接收整个数据包的唯一方法似乎是猜测其最大可能大小。
在阅读之前,我尝试获取一些可用字节:
ioctl(sock, FIONREAD, &nbytes);
但它总是返回 0。
对套接字的轮询总是失败,就好像根本没有可用的数据一样。
当启用非阻塞时(即fcntl(sock, F_SETFL, O_NONBLOCK);
) - read
总是失败 (-1), recv(sock, buf, buf_len, MSG_DONTWAIT)
。
那么有没有办法通过相应的非阻塞read
调用正确解析 RTP 数据包?
非阻塞是必不可少的,因为应该可以检查连接是否丢失并在必要时重新打开套接字。
与 TCP 是基于流的协议不同,UDP 是基于数据包的协议。 这意味着无论何时您从 UDP 套接字(多播与否)读取数据,您都会得到一个 UDP 数据报。 如果您的缓冲区不足以容纳整个数据报,则剩余的数据基本上会丢失。
确保您的缓冲区足够大以容纳完整的数据报。 如果您的网络支持端到端巨型帧,则意味着您的缓冲区应为 9000 字节,否则应为 1500 字节。
应该从套接字读取完整的缓冲区,然后解析它们。
可以创建一个 MTU 大小的缓冲区,从套接字读取到这个临时缓冲区,然后解析完整的缓冲区,然后采取行动。
可以使用 select() 或 poll() 来检查数据是否存在于套接字中。 当它可用时阅读它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.