Выбор протокола.
Что ж, вот и настала пора написать наше первое реально работающее SMS-приложение, чем и займемся. Для "удобоварения" мы разбили эту статью на несколько частей: сначала займемся некоторыми теоретическими вопросами (так, сущие пустяки -- опишем протокол :), а затем, не отвлекаясь, займемся кодированием.
В прошлый раз мы показали, как устанавливать связь с Сервис-центром, теперь же необходимо научиться работать собственно с протоколом -- формировать и "разбирать" пакеты. Но прежде, как легко догадаться, необходимо выбрать протокол. Эту сложнейшую задачу мы возьмем на себя ;) и остановимся на SMPP (Short Messages Peer-to-Peer). В пользу такого выбора говорят не только личные пристрастия, но и то, что данный протокол является наиблее широко распространненым, отлично проработан и превосходно документирован. Кроме того, не исключая возможности того, что читателям в реальности придется столкнуться с другими протоколами, отметим, что здесь ситуация сродни изучению иностранных языков: второй изучать легче чем первый, третий, чем второй и т. д.
Протокол SMPP.
Обзор.
Протокол SMPP позволяет , как не трудно догадаться, "внешним" устройствам обмениваться сообщениями с мобильной сетью (PLMN) посредством SMSC и определяет:
- Набор операций для обмена между SMSC и ESME, называемых также "командами" (command).
- Формат передаваемого пакета (PDU -- Protocol Data Unit), ассоциированный с каждой из операций.
- Формат ответного пакета (ACK или responce) для каждой PDU.
- Данные, которыми ESME должна обмениваться с SMSC в ходе таких операций.
Таким образом, вызову команды соответствует отправка PDU, поэтому мы иногда вместо "вызвать submit_sm" будем говорить "послать submit_sm" и наоборот. Следует также обратить внимание на то, что каждая из команд в рамках сессии должна быть подтверждена ответным пакетом (ACK), единственное исключение -- alert_notification PDU (впрочем, эта команда нам на первых порах не понадобится).
Сессии SMPP.
Обмен сообщениями с SMSC в формате протокола SMPP (кстати говоря -- не только) носит сессионный характер. Это означает, что обмен должен предваряться некоторой процедурой инициализации сессии и, в безошибочном варианте, за обменом должна следовать процедура закрытия сессии. В ходе процедуры открытия сессии ESME открывает соединение на уровне сокета, авторизуется и сообщает о цели открытия сессии:
- Прием сообщений. (приемник -- RECEIVER)
- Передача сообщений. (передатчик -- TRANSMITTER)
- Прием и передача сообщений. (приемо-передатчик -- TRANCEIVER)
Процедура инициализации выполняется с помощью вызова одной из команд bind_*:
- bind_receiver
- bind_transmitter
- bind_tranceiver
- OPEN -- Установлено сокетное соединение и послан один из запросов bind_*.
- BOUND_RX | BOUND_TX | BOUND_TRX -- Выполнена одна из команд bind_*. Соединение готово к приему | передаче | приему и передаче.
- CLOSED -- Выполнена команда unbind (рассмотрим позже) и соединение закрыто.
Команды (PDU) SMPP
Протокол SMPP версии 3.4 предоставляет следующий набор команд:
SMPP PDU Name | Required SMPP Session State | Issued by ESME | Issued by SMSC | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
bind_transmitter | OPEN | Yes | No | ||||||||
bind_transmitter_resp | OPEN | No | Yes | ||||||||
bind_receiver | OPEN | Yes | No | ||||||||
bind_receiver_resp | OPEN | No | Yes | ||||||||
bind_transceiver | OPEN | Yes | No | ||||||||
bind_transceiver_resp | OPEN | No | Yes | ||||||||
outbind | OPEN | No | Yes | ||||||||
unbind | BOUND_TX BOUND_RX BOUND_TRX | Yes Yes Yes | Yes Yes Yes | ||||||||
unbind_resp | BOUND_TX BOUND_RX BOUND_TRX | Yes Yes Yes | Yes Yes Yes | ||||||||
submit_sm | BOUND_TX BOUND_TRX | Yes Yes | No No | ||||||||
submit_sm_resp | BOUND_TX BOUND_TRX | No No | Yes Yes | ||||||||
submit_sm_multi | BOUND_TX BOUND_TRX | Yes Yes | No No | ||||||||
submit_sm_multi_resp | BOUND_TX BOUND_TRX | No No | Yes Yes | ||||||||
data_sm | BOUND_TX BOUND_RX BOUND_TRX | Yes Yes Yes | Yes Yes Yes | ||||||||
data_sm_resp | BOUND_TX BOUND_RX BOUND_TRX | Yes Yes Yes | Yes Yes Yes | ||||||||
deliver_sm | BOUND_RX BOUND_TRX | No No | Yes Yes | ||||||||
deliver_sm_resp | BOUND_RX BOUND_TRX | Yes Yes | No No | ||||||||
query_sm | BOUND_TX BOUND_TRX | Yes Yes | No No | ||||||||
query_sm_resp | BOUND_TX BOUND_TRX | No No | Yes Yes |
Команды с суффиксом _resp означают responce, т. е. ACK (мы также употребляем термин квитанция, и говорим, что ACK "квитирует" команду). Жирным помечены команды, которые мы рассмотрим (остальные в нашем простейшем случае нам пока не понадобятся).
Режимы (Modes) сообщений.
Протокол SMPP v3.4 поддерживает три режима обмена сообщениями. Мы не будем на этом особо останавливаться, просто упомянем, что в дальнейшем будем работать в т. н. Store and Forward Message Mode. В данном режиме сообщение сначала сохраняется в базе данных SMSC, а потом предпринимаются попытки его доведения, и, в зависимости от запроса, ESME уведомляется о достижении сообщением финального состояния (доведено/не доведено). Поддерживаются также Datagram Mode и Transaction Mode, о которых можно прочесть в соответствующей документации.
Типы данных SMPP
Все определяемые протоколом PDU представляют собой совокупность полей определенных типов, выстроенные друг за другом в определенном порядке. При работе в сети принято использовать понятие октет (octet) -- совокупность восьми битов (то что принято называть в программировании байтом) для того, чтобы подчеркнуть "восьмибитовость". Все определяемые SMPP типы привязаны к октету. Вот они:
- Integer -- Беззнаковое целое с указанной в каждом конкретном случае длиной в октетах.
- C-Octet String -- Серия ASCII литер, завершенная нулем.
- C-Octet String (Decimal) -- Серия литер (0-9), завершенная нулем
- C-Octet String (Hex) -- Серия литер (0-F), завершенная нулем.
- Octet String -- Серия октетов, не обязятельно завершенная нулем.
- TLV -- Tag-Length-Value. Используется для необязательных параметров. Данный тип возник из-за необходимость расширять уже существующие команды с сохранением обратной совместимости.Поскольку мы не собираемся таковые использовать :), то и останавливаться на этом не будем, хотя вопрос, вообще говоря, важный. Про TLV можно прочитать в спецификации протокола.
Формат PDU
Каждый пакет (PDU) состоит из двух частей:
- Заголовок (header). Обязательная.
- Тело (body). Необязательная.
Заголовок (header)
Заголовок имеет длину 16 октетов и состоит из 4-х полей:
- Command length -- Длина. 4 октета. Должен содержать общую длину пакета, включая и это поле.
- Command id -- Идентификатор команды. 4 октета. Указывает на тип команды. Принимает значения от 0x0 до 0x1FF для команд и от 0x800000000 до 0x8000001FF для ответов (ACK). Каждый пакет, представляющий собой ACK имеет command_id такой же, как и квитируемая команда, но с выставленным 31-м битом
- Command status -- Статус команды. 4 октета. Используется в ACK'ах, в командах выставляется в 0x0.
- Sequence number -- Номер последовательности. В каждом конкретном случае содержит уникальный номер отдельной команды (не путать с command_id) и позволяет ассоциировать ACK с командой. Назначается испускающей стороной произвольно из диапазона 0x1-0x7FFFFFFF. Повтор данного номера в рамках одной сессии, вообще говоря, не допустим. ACK должен иметь тот же номер, что и квитируемая команда.
No comments:
Post a Comment