Взаимодействие клиентов SIP. Часть 1



Месяц назад я начал свое знакомство с IP-телефонией, а именно с Lync и Asterisk. И заметил следующую картину: в сети очень много интересных статей по практической стороне вопроса (как и что делать) и очень мало внимания уделено теории (в конце статьи приведены ссылки). Если Вы хотите разобраться с SIP, то извольте либо читать RFC 3261, либо одну из «этих толстых книг». Это, естественно, полезно, но многим хочется в начале изучить некую выжимку, а уж потом бросаться в омут с головой. Эта статья как раз для таких людей.

Чтобы не перегружать читателя, я решил разбить статью на две части. В первой части мы рассмотрим работы протокола SIP при взаимодействии двух клиентов.

Простое взаимодействие клиентов

Взаимодействие клиентов в рамках SIP чаще всего осуществляется в виде диалога.

Диалог – это равноправное взаимодействие двух User Agent (UA) в виде последовательности SIP-сообщений между ними. При этом, существуют запросы, не образующие диалогов. Однако обо всем по-порядку.

Ниже приведен пример простого взаимодействия между двумя устройствами с поддержкой SIP:



Петр хочет начать обмен сообщениями с Иваном, для этого он посылает INVITE-сообщение с данными о типе сессии (простая, мультимедиа и т.д.). Сообщения имеют следующий формат: стартовая строка, одно или несколько полей заголовка, пустая строка, обозначающая конец полей заголовка и необязательное тело сообщения.



Стартовая строка содержит метод, Request-URI и версию SIP (актуальная – 2.0). Request-URI – это SIP-адрес ресурса, которому посылается запрос.



Поля заголовков имеют следующий формат: <Заголовок>: <Значение> <Перевод строки>

Первая строка начинается с заголовка Via. Каждое SIP-устройство, создающее или пересылающее сообщение, добавляет свой адрес в поле Via (как это происходит, я планирую показать в следующей части статьи). Обычно адрес представляет собой имя хоста, которое может быть разрешено с помощью DNS-запроса. Поле Via содержит версию SIP, знак “/”, пробел, транспортный протокол (UDP, TCP, TLS, SCTP), двоеточие, номер порта и branch – идентификатор транзакции. Ответы на этот запрос будут содержать такой же номер транзакции.



Чаще всего, значение branch начинается с “z9hG4bK”. Это значит, что запрос был сгенерирован клиентом, поддерживающим RFC 3261 и параметр уникален для каждой транзакции этого клиента.

Следующее поле, Max-Forwards, содержит относительно большое целое число. Каждый сервер SIP, который пересылает сообщение, уменьшает это число на единицу. Данное поле обеспечивает простой механизм обнаружение петель (loop).

Следом идут поля From и To, которые описывают отправителя и получателя запроса. Важно, что SIP-запросы маршрутизируются исходя из Request-URI, указанного в стартовой строке (см. выше). Это объясняется тем, что поля From и To могут быть изменены при пересылке. Если используется отображаемое имя (например, Ivan Ivanov), то SIP URI помещается внутрь пары угловых скобок. Параметр tag в поле From генерирует отправляющая сторона. В свою очередь принимающая сторона поместит свой tag в поле To.

Поле Call-ID – идентификатор вызова. Совокупность tag’ов из полей From и To и Call-ID однозначно идентифицируют данный диалог. Это необходимо, так как между клиентами может идти сразу несколько диалогов.

Следующее поле, Cseq, содержит порядковый номер запроса и название метода. В данном случае – INVTITE. Номер увеличивается с каждым новым запросом.

Поля Via, Max-Forwards, To, From, Call-ID и CSeq составляют минимальный необходимый набор полей заголовков SIP-сообщения.



Для сообщения INVITE также необходимо поле заголовка Contact, в котором содержится SIP URI, относящийся к коммуникационному устройству отправляющей стороны. Это поле используется, чтобы из всех устройств, которыми одновременно может пользоваться Петр, ответ был отправлен именно на данное устройство. Обратите внимание на значения полей From и Contact. Первый раз я не заметил разницу:



В сообщении присутствует опциональное поле Subject, то есть тема сообщения. Некоторые SIP-клиенты могут выводить значение этого поля на экран. Для маршрутизации и идентификации диалога поле не используется и может быть произвольным.

Поля Content-Type и Content-Length отвечают за описание тела сообщения. В данном случае будет использоваться Session Description Protocol (SDP). Размер сообщения вычисляется с учетом символов перевода строки:



Детальное описание работы протокола SDP заслуживает отдельной статьи, поэтому ниже приведена только краткая расшифровка:



В ответ на INVITE SIP-клиент Ивана отправляет два сообщения: 180 Ringing и 200 OK. Первое сообщает, что на стороне Ивана SIP-клиент подает звуковой сигнал звонка, второе – подтверждает установку диалога. Разберемся с каждым из них.

Так будет выглядеть сообщение 180 Ringing:



Бледным выделен текст, который не изменился по сравнению с сообщением INVITE.

Обратите внимание на поля заголовков To и From. Несмотря на то, что данное сообщение идет со стороны Ивана, значения полей остаются такими же, как были в первоначальном запросе (от Петра к Ивану). Это объясняется тем, что данные поля определяют направление запроса, а не сообщения.

Строка Via также перекочевала из исходного запроса, в конце строки добавлен параметр received этот параметр содержит IP-адрес, с которого пришел запрос. Обычно это адрес, который может быть получен путем разрешения URI, содержащегося в Via.

Как я и обещал, в поле To добавился tag, идентифицирующий диалог. Все последующие сообщения в рамках диалога будут содержать неизменные значения tag.

Наконец, в поле Contact содержится актуальный адрес Ивана.

Так выглядит сообщение 200 ОК, которое отправил SIP-клиент Ивана:



Думаю, смысл всех полей, относящихся к протоколу SIP теперь ясен.

В ответ на 200 ОК клиент Петра отправляет подтверждение:



Данное сообщение подтверждает, что клиента Петра успешно получил ответ от клиента Ивана. Оба клиента договорились о параметрах меди-сессии, которая будет осуществляться по протоколу RTP.

Обратите внимание, что номер последовательности CSeq все еще равен единице, но в качестве метода уже стоит ACK. Параметр Branch в поле Via содержит новый идентификатор транзакции, так как ACK, отправляемый в ответ на 200 OK считает новой транзакцией.

Теперь давайте рассмотрим, как происходит завершение медиа-сессии. Клиент Петра посылает BYE-запрос для завершение сессии:



Получив запрос на завершение сессии, клиент Ивана посылает подтверждение:



Сессия завершена.

Мы рассмотрели простой вариант работы протокола SIP. Обратите внимание, что в разные моменты времени клиенты Ивана и Петра выступали то в роли сервера, то в роли клиента, поэтому во всех SIP-клиентах должна функционировать как серверная (User Agent Server или UAS), так и клиентская часть (User Agent Client или UAC).

В следующей статье я планирую рассмотреть взаимодействие клиентов SIP с использованием Proxy-сервера и регистрацию клиентов на Proxy-сервере.

Что почитать по теме


1. RFC 3261. tools.ietf.org/html/rfc3261
2. Всё, что вы хотели знать о протоколе SIP (три части). Андрей Погребенник. samag.ru/archive/article/1831
3. SIP: Understanding the Session Initiation Protocol. Alan B. Johnston. www.amazon.com/SIP-Understanding-Initiation-Protocol-Telecommunications/dp/1607839954/ref=sr_1_1?ie=UTF8&qid=1375104428&sr=8-1&keywords=sip#
4. Протокол SIP. Гольдштейн Б.С., Зарубин А.А., Саморезов В.В. www.vef-kvant.ru/sip.htm
Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 11
  • –3
    Вы описали пример в котором sip:petr@mydom.org совершает звонок пользователю sip:ivan@domain.ru, при этом в примере нет промежуточных proxy серверов. В реальной жизни клиентам не назначают доменные имена с корнями (org, ru), правильнее на мой взгляд в вашем случае указывать IP адреса, хостов. Это я для того что-бы новички не путались. А статья отличная, спасибо, ждем продолжений.
    • 0
      Взаимодействие через Proxy будет во второй части. Спасибо на добром слове.
    • –1
      Спасибо большое за статью! Как раз то, что нужно и очень доходчиво. Жду продолжения!
      • +1
        Одна из фундаментальных проблем SIP-а в том, что это нагормождение различных костылей. Эйфелева башня из костылей. Одна треть костылей устарела, другая треть — никогда не используется. Я занимаюсь VoIP с 1999 года и убедился, что никто из разработчиков — ни клиентов, ни серверов — целиком не понимает всего стэка. А, по правде говоря, никакого стэка и нету. Есть просто десятки разрозненных документов и какие-то реализации.

        > Детальное описание работы протокола SDP заслуживает отдельной статьи

        Ох, как это знакомо :)
        Во всех подобных статьях и книгах про VoIP очень много внимания уделяется SIP-у, а про SDP и RTP никто не пишет — видимо, уже здоровья не хватает :)
        На самом деле реальный кошмар и хаос — это не сам SIP, а SDP и (как правило, кривые) реализации медиа-части в клиентах и серверах.
        • 0
          Постараюсь про SDP и RTP тоже написать — сам лучше начинаю разбираться, когда пишу.
          • 0
            А что вы предлагаете взамен с эквивалентным функционалом? H323 ещё страшнее.
            • 0
              Да что тут предложишь…
              Жалкое зрелище… Душераздирающее зрелище… Кошмар! © Ослик Иа
            • 0
              На самом деле эта проблема возникает в результате отсутствия соответствующих встреч / семинаров разработчиков. Я задумывался над организацией докладов, но дальше мыслей дело увы пока не пошло, постараюсь все таки реализовать задуманное в ноябре/декабре. Думаю всем будет полезно послушать и пообщаться.
              • 0
                Совершенно согласен. Один только парсинг синтаксиса SIP чего стоит, для этого нужно применять «тяжелую артиллерию» в виде всяких Yacc и т.п. Далее, нагромождение всяких «branch», «tag», которые необходимо отслеживать. Плохая поддержка NAT, а ведь во время разработки этих протоколов (по меньшей мере второй версии) многие клиенты уже сидели за NAT. И главное — с какой целью все эти сложности? Нужно всего лишь сообщить «провайдеру», что мы хотим позвонить такому-то абоненту, дайте нам его IP-адрес и порт. Про SDP вообще молчу. Еще один синтаксис, еще один парсер. И самая главная информация — IP-адрес абонента и порт — кодируется в нем ну очень уж неочевидно.

                Единственный нормальный протокол в этой системе — RTP. Он несколько избыточный, но не смертельно. Реализовывать поддержку RTP сложно, особенно приемник, но это проблема не RTP, а фундаментальное свойство решаемой задачи передачи сигнала в реальном времени.
                • 0
                  Что касается NAT, если дойдут руки, то опишу ICE, STUN и TURN.
                  • 0
                    Какую поддержку NAT вам надо? На правильных серверах все и так работает замечательно. Если у вас исключительно примитивные потребности «позвонить», то это не значит что всем остальным тоже ничего не надо.

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