Artikelmaterialet är hämtat från min .

Vi använder TShark för att analysera RTP-paket

Tidigare Vi har byggt ett schema för fjärrstyrning med en generator och en detektor för ton-signaler, där kommunikationen skedde via en RTP-ström.
I denna artikel fortsätter vi att undersöka överföring av ljudsignal med hjälp av RTP-protokollet. Först delar vi vår testapplikation i en sändare och en mottagare och lär oss att analysera RTP-strömmen med hjälp av en nätverkstrafikanalysator.
Så för att vi tydligare ska se vilka programkomponenter som ansvarar för att överföra RTP och vilka som ansvarar för mottagningen, delar vi vår fil mstest6.c i två fristående program, en sändare och en mottagare, där gemensamma funktioner kommer att flyttas till en tredje fil, som vi kommer att kalla mstest_common.c, den kommer att kopplas in av sändaren och mottagaren med hjälp av include-direktivet:
/* Файл mstest_common.c Общие функции для передатчика и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/msrtp.h>
#include <ortp/rtpsession.h>
#include <ortp/payloadtype.h>
define PCMU 0
/*---------------------------------------------------------*/
/* Функция регистрации типов полезных нагрузок. */
void register_payloads(void)
{
/* Регистрируем типы нагрузок в таблице профилей. Позднее, по индексу взятому
из заголовка RTP-пакета из этой таблицы будут извлекаться параметры
нагрузки, необходимые для декодирования данных пакета. */
rtp_profile_set_payload (&av_profile, PCMU, &payload_type_pcm8000);
}
/*---------------------------------------------------------*/
/* Эта функция создана из функции create_duplex_rtpsession() в audiostream.c медиастримера2. */
static RtpSession *create_rtpsession (int loc_rtp_port, int loc_rtcp_port, bool_t ipv6, RtpSessionMode mode)
{
RtpSession *rtpr; rtpr = rtp_session_new ((int) mode);
rtp_session_set_scheduling_mode (rtpr, 0);
rtp_session_set_blocking_mode (rtpr, 0);
rtp_session_enable_adaptive_jitter_compensation (rtpr, TRUE);
rtp_session_set_symmetric_rtp (rtpr, TRUE);
rtp_session_set_local_addr (rtpr, ipv6 ? "::" : "0.0.0.0", loc_rtp_port, loc_rtcp_port);
rtp_session_signal_connect (rtpr, "timestamp_jump", (RtpCallback) rtp_session_resync, 0);
rtp_session_signal_connect (rtpr, "ssrc_changed", (RtpCallback) rtp_session_resync, 0);
rtp_session_set_ssrc_changed_threshold (rtpr, 0);
rtp_session_set_send_payload_type(rtpr, PCMU);
/* По умолчанию выключаем RTCP-сессию, так как наш пульт не будет использовать
её. */
rtp_session_enable_rtcp (rtpr, FALSE);
return rtpr;
}
Nu filen för den fristående sändaren:
/* Файл mstest6.c Имитатор пульта управления (передатчика). */
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>
#include "mstest_common.c"
/*----------------------------------------------------------*/
int main()
{
ms_init();
/* Создаем экземпляры фильтров. */
MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
/* Создаем фильтр кодера. */
MSFilter *encoder = ms_filter_create_encoder("PCMU");
/* Регистрируем типы нагрузки. */
register_payloads();
/* Создаем RTP-сессию передатчика. */
RtpSession *tx_rtp_session = create_rtpsession (8010, 8011, FALSE, RTP_SESSION_SENDONLY);
rtp_session_set_remote_addr_and_port(tx_rtp_session,"127.0.0.1", 7010, 7011);
rtp_session_set_send_payload_type(tx_rtp_session, PCMU);
MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID);
ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, tx_rtp_session);
/* Создаем источник тактов - тикер. */
MSTicker *ticker_tx = ms_ticker_new();
/* Соединяем фильтры передатчика. */
ms_filter_link(voidsource, 0, dtmfgen, 0);
ms_filter_link(dtmfgen, 0, encoder, 0);
ms_filter_link(encoder, 0, rtpsend, 0);
/* Подключаем источник тактов. */
ms_ticker_attach(ticker_tx, voidsource);
/* Настраиваем структуру, управляющую выходным сигналом генератора. */
MSDtmfGenCustomTone dtmf_cfg;
dtmf_cfg.tone_name[0] = 0;
dtmf_cfg.duration = 1000;
dtmf_cfg.frequencies[0] = 440;
/* Будем генерировать один тон, частоту второго тона установим в 0. */
dtmf_cfg.frequencies[1] = 0;
dtmf_cfg.amplitude = 1.0;
dtmf_cfg.interval = 0.;
dtmf_cfg.repeat_count = 0.;
/* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает
* цикл и работу программы. */
char key='9';
printf("Нажмите клавишу команды, затем ввод.n"
"Для завершения программы введите 0.n");
while(key != '0')
{
key = getchar();
if ((key >= 49) && (key <= 54))
{
printf("Отправлена команда: %cn", key);
/* Устанавливаем частоту генератора в соответствии с
* кодом нажатой клавиши. */
dtmf_cfg.frequencies[0] = 440 + 100*(key-49);
/* Включаем звуковой генератор c обновленной частотой. */
ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM, (void*)&dtmf_cfg);
}
/* Укладываем тред в спячку на 20мс, чтобы другие треды
* приложения получили время на работу. */
ms_usleep(20000);
}
}Och slutligen, filen för mottagaren:
/* Файл mstest7.c Имитатор приемника. */
include <mediastreamer2/mssndcard.h>
include <mediastreamer2/mstonedetector.h>
include <mediastreamer2/msrtp.h>
/* Подключаем заголовочный файл с функциями управления событиями медиастримера.*/
include <mediastreamer2/mseventqueue.h>
/* Подключаем файл общих функций. */
include "mstest_common.c"
/* Функция обратного вызова, она будет вызвана фильтром, как только он обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,MSToneDetectorEvent *ev)
{
printf("Принята команда: %sn", ev->tone_name);
}
/*----------------------------------------------------------*/
int main()
{
ms_init();
/* Создаем экземпляры фильтров. */
MSSndCard *card_playback = ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
MSFilter *snd_card_write = ms_snd_card_create_writer(card_playback);
MSFilter *detector = ms_filter_new(MS_TONE_DETECTOR_ID);
/* Очищаем массив находящийся внутри детектора тонов, он описывает
* особые приметы разыскиваемых сигналов.*/
ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);
/* Подключаем к фильтру функцию обратного вызова. */
ms_filter_set_notify_callback(detector, (MSFilterNotifyFunc)tone_detected_cb, NULL);
/* Создаем массив, каждый элемент которого описывает характеристику
* одного из тонов, который требуется обнаруживать:
Текстовое имя
* данного элемента, частота в герцах, длительность в миллисекундах,
* минимальный уровень относительно 0,775В. */
MSToneDetectorDef scan[6]=
{
{"V+",440, 100, 0.1}, /* Команда "Увеличить громкость". */
{"V-",540, 100, 0.1}, /* Команда "Уменьшить громкость". */
{"C+",640, 100, 0.1}, /* Команда "Увеличить номер канала". */
{"C-",740, 100, 0.1}, /* Команда "Уменьшить номер канала". */
{"ON",840, 100, 0.1}, /* Команда "Включить телевизор". */
{"OFF", 940, 100, 0.1}/* Команда "Выключить телевизор". */
};
/* Передаем "приметы" сигналов детектор тонов. */
int i;
for (i = 0; i < 6; i++)
{
ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN, &scan[i]);
}
/* Создаем фильтр декодера */
MSFilter *decoder=ms_filter_create_decoder("PCMU");
/* Регистрируем типы нагрузки. */
register_payloads();
/* Создаем RTP-сессию приемника. */
MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
RtpSession *rx_rtp_session = create_rtpsession (7010, 7011, FALSE, RTP_SESSION_RECVONLY);
ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rx_rtp_session);
/* Создаем источник тактов - тикер. */
MSTicker *ticker_rx = ms_ticker_new();
/* Соединяем фильтры приёмника. */
ms_filter_link(rtprecv, 0, decoder, 0);
ms_filter_link(decoder, 0, detector, 0);
ms_filter_link(detector, 0, snd_card_write, 0);
/* Подключаем источник тактов. */
ms_ticker_attach(ticker_rx, rtprecv);
char key='9';
printf( "Для завершения программы введите 0.n");
while(key != '0')
{
key = getchar();
/* Укладываем тред в спячку на 20мс, чтобы другие треды * приложения получили время на работу. */
ms_usleep(20000);
}
}
Vi kompilera sändaren och mottagaren, och sedan kör vi varje i sin egen konsol. Därefter bör det fungera som tidigare — vi ska bara mata in siffror från 1 till 6 i sändarens konsol, och svaren på dem bör visas i mottagarens konsol. Toner bör kunna höras dynamiskt. Om allt fungerar så har vi etablerat en anslutning mellan sändaren och mottagaren — det sker en kontinuerlig överföring av RTP-paket från sändaren till mottagaren.
Nu är det dags att installera trafikanalysatorn, för detta installerar vi den konsolbaserade versionen av det utmärkta programmet Wireshark — den kallas TShark. Jag valde TShark för att underlätta beskrivningen av programhanteringen. Med Wireshark skulle jag behöva mängder av skärmdumpar som snabbt kan bli föråldrade med nya versioner av Wireshark.
Om du kan använda Wireshark, kan du använda det för att studera våra exempel. Men även då rekommenderar jag att du lär dig TShark, eftersom det kommer att hjälpa dig att automatisera testning av dina VoIP-applikationer och även utföra fjärrövervakning.
Installera TShark med kommandot:
$ sudo apt-get install tsharkTraditionellt kontrollerar vi installationsresultatet genom att be om programversionen:
$ tshark --versionOm vi får ett rimligt svar fortsätter vi vidare.
Eftersom våra paket bara går inom datorn kan vi be TShark att visa endast sådana paket. För detta behöver vi välja paketfångst från gränssnittet loopback (återkoppling), och ge TShark alternativet -i lo:
$ sudo tshark -i loI konsolen börjar meddelanden om de paket som skickas av vår sändare direkt att visas (konstant, oavsett om vi tryckte på knappen på fjärrkontrollen eller inte). Det kan finnas program på din dator som också skickar paket via den lokala slingan, i så fall får vi en blandning av våra och andras paket. För att vara säkra på att vi bara ser paketen som skickas av vår fjärrkontroll i listan, lägger vi till ett filter baserat på portnumret. Genom att trycka på Ctrl-C stoppar vi avlyssningen och skriver in filtret på det portnummer som används av fjärrkontrollen som destinationsport för sin överföring (8010): -f "udp port 8010". Nu kommer vår kommandorad att se ut så här:
$ sudo tshark -i lo -f "udp port 8010"I konsolen kommer utdata att se ut så här (de första 10 raderna):
1 0.000000000 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
2 0.020059705 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
3 0.040044409 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
4 0.060057104 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
5 0.080082311 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
6 0.100597153 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
7 0.120122668 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
8 0.140204789 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
9 0.160719008 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172
10 0.180673685 127.0.0.1 → 127.0.0.1 UDP 214 8010 → 7010 Len=172Det är fortfarande inte paket utan en numrerad lista över händelser där varje rad är ett meddelande om ett paket som upptäckts på gränssnittet. Eftersom vi redan har sett till att filtrera paketen, ser vi i listan endast meddelanden om paketen från vår sändare. Låt oss nu avkoda denna tabell enligt kolumnnumren:
Händelsenummer.
Tidpunkten för dess inträffande.
IP-adressen för paketkällan och IP-adressen för paketmottagaren.
Paketprotokollet, visat som UDP, eftersom RTP-paket överförs som nyttolast inuti UDP-paket.
Störrelsen på paketet i byte.
Källportnumret för paketet och mottagarens portnummer.
Storleken på nyttolasten i paketet, härifrån kan vi dra slutsatsen att vår sändare skapar RTP-paket med en storlek av 172 byte, som, likt en anka i en kista, finns inuti ett UDP-paket med en storlek av 214 byte.
Nu är det dags att titta inuti UDP-paketen, för detta kör vi TShark med en utökad uppsättning av nycklar:
sudo tshark -i lo -f "udp port 8010" -P -V -O rtp -o rtp.heuristic_rtp:TRUE -xSom ett resultat kommer programmets utdata att berikas — varje händelse kommer att få en avkodning av innehållet i det paket som orsakade det. För att bättre kunna granska utdata kan du antingen stoppa TShark genom att trycka på Ctrl-C, eller duplicera dess utdata till en fil genom att lägga till en pipeline till tee-programmet med ett filnamn, tee <filnamn>:
$ sudo tshark -i lo -f "udp port 8010" -P -V -O rtp -o rtp.heuristic_rtp:TRUE -x | tee log.txtNu ska vi titta på vad vi fick i filen, här är det första paketet från den:
1 0.000000000 127.0.0.1 → 127.0.0.1 RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6B8B4567, Seq=58366, Time=355368720
Frame 1: 214 bytes on wire (1712 bits), 214 bytes captured (1712 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1User Datagram Protocol, Src Port: 8010, Dst Port: 7010
Real-Time Transport Protocol [Stream setup by HEUR RT (frame 1)]
[Setup frame: 1]
[Setup Method: HEUR RT]
10.. .... = Version: RFC 1889 Version (2)
..0. .... = Padding: False
...0 .... = Extension: False
.... 0000 = Contributing source identifiers count: 0
0... .... = Marker: False
Payload type: ITU-T G.711 PCMU (0)
Sequence number: 58366 [Extended sequence number: 58366]
Timestamp: 355368720
Synchronization Source identifier: 0x6b8b4567 (1804289383)
Payload: ffffffffffffffffffffffffffffffffffffffffffffffff...
0000 00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 ..............E.
0010 00 c8 3c 69 40 00 40 11 ff b9 7f 00 00 01 7f 00 ..<i@.@.........
0020 00 01 1f 4a 1b 62 00 b4 fe c7 80 00 e3 fe 15 2e ...J.b..........
0030 7f 10 6b 8b 45 67 ff ff ff ff ff ff ff ff ff ff ..k.Eg..........
0040 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
0050 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
0060 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
0070 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
0080 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
0090 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
00a0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
00b0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
00c0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
00d0 ff ff ff ff ff ff ......I nästa artikel kommer vi att ägna oss åt att analysera informationen som finns i denna utskrift och nödvändigtvis tala om den interna strukturen hos RTP-paketet.
Källa: habr.com
