У меня проблемы с чтением 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;
}
Если я читаю заголовок RTP плюс полезную нагрузку в одной операции read
, я получаю весь пакет. Однако, если я сначала пытаюсь получить заголовок RTP, а затем - пользовательский заголовок в полезной нагрузке - 2-й read
всегда получает вместо этого следующий заголовок RTP, отбрасывая все присоединенные данные. Поскольку длина полезной нагрузки может варьироваться, кажется, что единственный способ получить целый пакет - угадать его максимально возможный размер.
Я пытался получить количество доступных байтов перед чтением:
ioctl(sock, FIONREAD, &nbytes);
но всегда возвращает 0.
Опрос в сокете всегда завершается неудачей, как будто данные вообще не доступны.
Когда включена неблокирующая функция (т. Е. fcntl(sock, F_SETFL, O_NONBLOCK);
) - read
всегда терпит неудачу (-1), так же, как и recv(sock, buf, buf_len, MSG_DONTWAIT)
.
Так есть ли способ правильно проанализировать пакеты RTP с помощью последовательных неблокирующих вызовов read
?
Non- блокировка необходима, потому что должна быть возможность проверить, было ли потеряно соединение, и при необходимости заново открыть сокет.