LINUX.ORG.RU

RTP-analyzer (c++, linux)


0

1

Добрый день! Мне необходимо написать rtp-analyzer, подобный http://mmlab.disi.unitn.it/wiki/index.php/Analyzer. К сожалению, исходный код analyzer найти не удалось,а без него не могу понять, как сервер,принимающий udp-датаграммы (по сути это udp-сокет),понимает,что одна udp-датаграмма закончилась и началась другая, как он идентифицирует датаграммы, содержащие RTP. Мне представлялось, что udp-сокет работает с данными, то есть обработка udp-заголовка выполняется системно и скрыта от программиста. Может, кто-то сталкивался с подобной задачей?Интересует, главным образом, реализация. Спасибо!


что одна udp-датаграмма закончилась и началась другая

recvfrom (а подозреваю что и все остальные) вернут ровно один пакет за раз.

ЗЫ по ссылкам не ходил

true_admin ★★★★★
()

А в чем проблема? UDP - протокол дейтаграммный, в отличие от TCP. Вызов recvfrom (если ему передать буфер достаточного размера) вернет ровно 1 дейтаграмму. В Вашем случае 1 RTP пакет (состоящий из заголовка RTP и пэйлоада RTP). Проверяете и анализируете, что хотите (если отправитель Вас устроил).

Будут вопросы - пишите. Постараюсь ответить.

nocomer
()

Мне представлялось, что udp-сокет работает с данными, то есть обработка udp->заголовка выполняется системно и скрыта от программиста.

rtp-заголовок внутри udp пакета http://www.opennet.ru/docs/RUS/inet_book/4/44/rtp_4492.html

можно использовать pcap

anonymous
()
Ответ на: комментарий от anonymous

Спасибо, вопросы есть. То есть udp-сокет считывает данные вместе с заголовком?Не совсем ясно,что Вы имеете в виду,когда говорите за раз...Вот у меня есть буфер достаточного размера, я в неблокирующем (например,мониторю доступность дескриптора с помощью вызова poll) режиме в цикле вызываю метод считывающий поступающие udp-данные и анализирую данные считавшиеся в этот буфер. Пусть у меня считалось в буфер две датаграммы и часть третьей,такое же может быть?Я имею неврное представление?

Masha
() автор топика
Ответ на: комментарий от Masha

Все дейтаграммы складываются в очередь и извлекаются последовательно по одной (это с некоторыми оговорками). Если у тебя приемные буфера достаточного размера, ты после вызова recvfrom получаешь дейтаграмму и её размер. Но если размер меньше чем нужно, ты тоже из очереди извлечешь дейтаграмму, но поимеешь только её часть. Об этом тебя уведомит соответствующий флаг.

meil
()
Ответ на: комментарий от Masha

recvfrom ->recvmsg Примерно так:

static result_type receive_from(socket_type sd,
                iobuf_type* iobuf, std::size_t count,
                sockaddr_type* addr, std::size_t* addrlen,
                int& flags) throw()
{
    msghdr msg = msghdr();
    msg.msg_name = addr;
    msg.msg_namelen = static_cast<socklen_t>(*addrlen);
    msg.msg_iov = iobuf;
    msg.msg_iovlen = count;

    result_type result = ::recvmsg(sd, &msg, flags);

    *addrlen = static_cast<std::size_t>(msg.msg_namelen);
    flags = msg.msg_flags;

    return result;
}
или так:
static result_type receive_from(socket_type sd,
                iobuf_type* iobuf, std::size_t count,
                sockaddr_type* addr, std::size_t* addrlen,
                int& flags) throw()
{
    DWORD bytes_transferred = 0;
    DWORD recv_flags = flags;
    int ret_addrlen = addrlen ? static_cast<int>(*addrlen) : 0;
    result_type result = ::WSARecvFrom(sd, iobuf, count,
            &bytes_transferred, &recv_flags, addr, &ret_addrlen, 0, 0);
    flags = recv_flags;
    if (addrlen)
        *addrlen = static_cast<std::size_t>(ret_addrlen);
    return (result == 0 ? bytes_transferred : (result_type)has_error);
}

meil
()
Ответ на: комментарий от Masha

Это точно. Как уже несколько раз сказали: UDP - дейтаграммный (recvfrom и аналоги вернет 1 дейтаграмму), TCP - потоковый (recvfrom и аналоги вернут сколько есть данных).

Так что, Masha, резервируйте буфер достаточного размера (0xffff - хватит для любого UDP), а то что Вы будете с частью дейтаграммы делать (даже если узнали с помощью флага, полученного от recvmsg, что прочитали только часть (из-за слишком маленького буфера).

Также не забывайте, что UDP не гарантирует порядок и доставку пакетов, т.е. некоторые пакеты могут быть перемешаны, либо отсутствовать.

Очевидные вещи пишу, извините, но мне показалось, что следует Вам напомнить.

По поводу Вашего вопроса:

То есть udp-сокет считывает данные вместе с заголовком?

UDP-заголовка в прочитанном пакете, конечно, не будет. Будет RTP заголовок, после которого RTP payload (аудио, видео или что там у Вас передается).

nocomer
()
Ответ на: комментарий от nocomer

Итак, в буфере лежат данные без заголовка, то есть если послать датаграмму, в которой нет данных вызов recvfrom вернет нуль, в буфере ничго не будет?И остался вопрос, как отличить данные RTP, от каких-либо других данных, то есть идентифицировать датаграммы, содержащие rtp?

Masha
() автор топика
Ответ на: комментарий от Masha

Masha, такие вещи проще делать на высокоуровневых языках, а не на C. Вообще, в RFC есть список примет, по которым можно отличить RTP от не-RTP.

plm ★★★★★
()

Здравствуй, Маша. Можно маленькую просьбу?

Сфотографируйся на фоне ЛОРа с табличкой «Привет, isden!». Желательно попадание синиц в кадр )

С уважением, доброжелатель.

LongLiveUbuntu ★★★★★
()
Ответ на: комментарий от Masha

есть если послать датаграмму, в которой нет данных вызов recvfrom вернет нуль, в буфере ничго не будет?

Да, если отправить UDP нулевой длины, то recvfrom вернет 0.

как отличить данные RTP, от каких-либо других данных, то есть идентифицировать датаграммы, содержащие rtp?

UDP не предоставляет способа идентифицировать вышележащий протокол. Опознать RTP можно только эвристически на основе анализа содержимого пакета (если, конечно, порт не известен).

nocomer
()
Ответ на: комментарий от nocomer

А как извлечь последовательный номер RTP пакета?Допустип, данные считались в буфер unsigned char* buffer. Мне нужно получить десятичное представление втрого и третьего байта (То есть число, записанное в этих двух байтах ).

Masha
() автор топика
Ответ на: комментарий от anonymous

разработчики под ARM, MIPS и просто люди, знакомые с выравниванием, посылают вам пламенный привет

nocomer
()
Ответ на: комментарий от Masha

Маша, вы чем там злоупотребляете, если не секрет?

Наберите в гугле что-то типа rtp header struct, и вам откроются Тайные Знания. Например, знания о том как этот заголовок выглядит и как его нужно парсить. Да чего там, может повезет и увидите готовые парсеры RTP. Надо только попробовать

P.S. Приходите на сеновал, попрограммируем при луне

P.P.S. Ну или переходите на амфетамины

anonymous
()
Ответ на: комментарий от anonymous

Хотя, вы же в гугл не пойдете? А вам щас насоветуют тут. В общем, это должно выглядеть приблизительно так (в unsigned char* buffer принятый пакет):

typedef struct rtp_header {
        unsigned int version:2;   /* protocol version */
        unsigned int p:1;         /* padding flag */
        unsigned int x:1;         /* header extension flag */
        unsigned int cc:4;        /* CSRC count */
        unsigned int m:1;         /* marker bit */
        unsigned int pt:7;        /* payload type */

       uint16_t seq;              /* sequence number */
       uint32_t ts;               /* timestamp */
       uint32_t ssrc;             /* synchronization source */
       uint32_t csrc[1];          /* optional CSRC list */
} rtp_header;

/* ... */

rtp_header *hdr;
unsigned int sequence;

/* ... */

hdr = (rtp_header *)buffer;

sequence = ntohs(hdr->seq);

printf("#Seq: %u\n", sequence);

Код, понятное дело, не проверял, у меня пакетов этих под рукой нет, но если и ошибся, то не сильно

anonymous
()
Ответ на: комментарий от nocomer

Спаcибо большое!Там только должно быть memcpy(&seq, buffer+2,2), но это неважно. Не подскажете, как реализовать следующее: выдавать сообщение о числе полученных и потеренных RTP-пакетах после остановки RTP-анализатора (комбинации Ctrl+C)?Нужно каким-то образом обрабатывать сигнал?

Masha
() автор топика
Ответ на: комментарий от anonymous

Спасибо!тоже пока не проверяла,но,возможно,формировать структуру RTP-заголовка было бы более правильным.

Masha
() автор топика
Ответ на: комментарий от Masha

формировать структуру RTP-заголовка было бы более правильным

Ну. Вам же еще нужно будет другие поля оттуда брать.

Вот я не поленился, сходил по ссылке, посмотрел на этот анализатор. Вам точно именно такой нужен? Если да, то зачем по Ctrl-C что-то отбивать? Впрочем, как хотите, вот приблизительный код для обработки SIGINT. Проверял, работает :-)

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

/*
Статистику можно хранить в глобальных переменных
 */

void
sigint_handler(int sn)
{
        printf("SIGINT\n");
        /* Тут можно сделать exit(EXIT_SUCCESS), например */
}


int
main()
{
        signal(SIGINT, sigint_handler);
        for (;;) {}
        return EXIT_SUCCESS;
}

anonymous
()
Ответ на: комментарий от nocomer

Вы писали:«UDP - протокол дейтаграммный, в отличие от TCP. » А что, если теперь задача стоит по-другому, и требуется написать клиент-серверное приложение, в котором клиент передает серверу файл?При считывании файла на сервере могут возникнуть проблемы?

Masha
() автор топика
Ответ на: комментарий от Masha

А в чем вопрос?

Да, TCP - потоковый протокол, гарантирующий доставку и порядок байтов. Значит, данные на сервер придут в нужном порядке, без потерь (если это физически возможно). Единственное, что будучи потоковым протоколом, TCP не сохранит границы отправляемых пакетов, т.е. отправив 3 раза по 300 байтов, Вы можете получить 1 раз все 900 (или как-нибудь по-другому).

Для TCP recv() вернет 0, когда другой конец (клиент) сделает корректный shutdown(). Простейший сценарий - делаете коннект на клиенте и гоните файл send-ами, как файл закончился - закрываете соединение. На сервере, соответственно, listen, accept и принимаете, пока данные не кончатся (т.е. вплоть до shutdown) и ошибки возможные проверяете в recv/send.

Можно поинтересней, конечно, сделать: реконнекты при разрыве соединения, отпраку данных несколькими сокетами и т.д. Но это Вы уж сами, хорошо?

Не знаю, ответил - не ответил.

nocomer
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.