div.main {margin-left: 20pt; margin-right: 20pt} С.Кадаков
sgerr@hotmail.com
SMS-приложение. Часть 2.
Глава 1 Процедура авторизации.
Мы начинаем обсуждать команды протокола. В нашем, самом
первом, приложении нам их понадобится совсем немного. Начнем с процедуры
авторизации, выполняемой одной из команд семейства BIND.
Команды BIND.
Как уже говорилось, это семейство включает три команды:
bind_receiver -- сообщает SMSC, что ESME подключается для
приема сообщений. Такой режим (только прием) характерен, например, для
пэйджинговых шлюзов.
bind_transmitter -- сообщает SMSC, что ESME подключается для
передачи сообщений. Данный режим используется, в частности, при
организации рассылок (в том числе, к сожалению, и спама).
bind_transceiver -- сообщает SMSC, что ESME подключается для
приема и передачи (т. е. в полнодуплексной моде). Этот режим удобен для
создания полнофункциональных шлюзов.
Ниже мы рассмотрим каждую из команд в отдельности и
приведем формат пакетов. Как уже отмечалось, все команды (пакеты) SMPP
должны предваряться заголовком. В заголовке команды поле command_id должно
содержать соответствующее значение.
bind_receiver. command_id = 0x01
Тело пакета bind_receiver состоит из следующих
полей:
Field name
Size (octets)
Type
Description
system_id |
Var. max 16 |
C-Octet String |
Идентифицирует ESME. Можно рассматривать это поле, как
"username". |
password |
Var. max 9 |
C-Octet String |
Пароль для аутентификации. |
system_type |
Var. max 13 |
C-Octet String |
Необязательное. Используется для указания категории
ESME, например "WWW", "E-MAIL" и т. д. Если не используется, должно
содержать один октет NULL (0x0) |
interface_version |
1 |
Integer |
Идентифицирует версию протокола SMPP, поддерживаемую
ESME. 0x00-0x33 указывают, что поддерживается версия 3.3 или более
ранняя. 0x34 указывает, что поддерживается версия 3.4 |
addr_ton |
1 |
Integer |
Указывает тип адреса (TON - Type Of Number) ESME. (см.
ниже). Если неизвестен, выставляется в NULL |
addr_npi |
1 |
Integer |
Указывает индикатор плана номеров (NPI -- Numbering
Plan Indicator). (см. ниже). Если неизвестен, выставляется в
NULL |
address_range |
Var. max 41 |
C-Octet String |
Адрес или диапазон адресов, обслуживаемых ESME. Если
неизвестен, выставляется в NULL |
bind_receiver_resp. command_id = 0x80000001
Тело пакета bind_receiver_resp состоит из
следующих полей (*):
Field name
Size (octets)
Type
Description
system_id |
Var. max 16 |
C-Octet String |
Подтвержденный идентификатор ESME. |
sc_interface_version |
- |
TLV |
Необязательное поле в формате TLV. Информирует о
версии протокола SMPP, поддерживаемой SMSC |
(*) -- В том случае, если поле command_status заголовка содержит
ненулевое значение (т. е. информирует об ошибке) тело пакета не
передается.
bind_transmitter. command_id = 0x02
Формат и назначение полей тела пакета
bind_transmitter совпадает с форматом и назначением полей тела
пакета bind_receiver.
bind_transmitter_resp. command_id = 0x80000002
Формат и назначение полей тела пакета
bind_transmitter_resp совпадает с форматом и назначением полей тела
пакета bind_receiver_resp.
bind_tranceiver. command_id = 0x03
Формат и назначение полей тела пакета
bind_transceiver совпадает с форматом и назначением полей тела
пакета bind_receiver.
bind_tranceiver_resp. command_id = 0x80000003
Формат и назначение полей тела пакета
bind_transceiver_resp совпадает с форматом и назначением полей тела
пакета bind_receiver_resp.
Параметры TON и NPI.
Параметры TON и NPI не являются специфичными для
протокола SMPP, поэтому мы здесь не будем останавливаться на них подробно,
а просто приведем их возможные значения (подробнее об этих параметрах
можно прочитать в документации GSM):
TON
Value (bin)
Unknown |
00000000 |
International |
00000001 |
National |
00000010 |
Network Specific |
00000011 |
Subscriber Number |
00000100 |
Alphanumeric |
00000101 |
Abbreviated |
00000110 |
Reserved |
All others |
NPI
Value (bin)
Unknown |
00000000 |
ISDN (E163/E164) |
00000001 |
Data (X.121) |
00000011 |
Telex (F.69) |
00000100 |
Land Mobile (E.212) |
00000110 |
National |
00001000 |
Private |
00001001 |
ERMES |
00001010 |
Internet (IP) |
00001100 |
WAP Client Id (to be defined by WAP Forum) |
00010010 |
Reserved |
All others |
Generic Negative Result (generic_nack)
Как уже отмечалось, любая из команд, испущенная той или
иной из сторон должна квитироваться ACK'ом (за единственным, упомянутым в
прошлой статье исключением). При этом поле command_id заголовка ACK'а
должно содержать соответствующее значение (равное command_id оригинальной
команды с выставленным 31-м битом), а поле sequence_number заголовка
должно указывать номер транзакции оригинальной команды. Однако в некоторых
случаях, в частности, когда принимающая сторона не может распознать
заголовок оригинальной команды -- например, при возникновении "мусора" в
TCP/IP канале -- информация, необходимая для формирования корректного
ACK'а может оказаться недоступной. В таких случаях принимающая сторона
отвечает специальным пакетом, называемым generic_nack (command_id =
0x80000000). Данный пакет состоит из одного заголовка с указанным
command_id. Поле command_status содержит соответствующий код ошибки, а
поле sequence_number может содержать NULL (0x0), если не удалось
распознать номер транзакции оригинальной команды.
Замечания.
Несколько слов по поводу направления передачи данных по
соединениям, т. к. могут возникать недоразумения, связанные с названиями
сессий. Например, если ESME авторизовалось с помощью команды
bind_transmitter и сессия перешла в состояние BOUND_TX, не
следует думать, что SMSC не может передавать данные в такое
соединение (т. е., что программист избавлен от вызова recv(2) с
этим сокетом). Напротив, еще раз подчеркнем, что ACK'и передаются в
рамках того же соединения (т. е. в тот же сокет), что и оригинальные
команды. С другой стороны, разумеется, входящие сообщения (т. е. от SMSC к
ESME) не могут быть переданы по соединению, находящемуся в
BOUND_TX. Это важный момент и вот почему: как мы договорились, мы
будем работать в т. н. Store And Forward Mode, при этом сообщения
сначала помещаются в базу данных SMSC, а потом предпринимаются попытки их
доведения. Таким образом, факт помещения в базу данных (подтверждаемый
ACK'ом) еще не означает, что конечный пользователь получил данное
сообщение, кроме того, оно вообще может быть не доведено до истечения
срока годности в том случае, например, если аппарат пользователя остается
отключенным не протяжении нескольких дней. SMSC сигнализирует о переходе
сообщения в финальное состояние (доставлено/не может быть доставлено) с
помощью (специального вида) команды deliver_sm, т. е. той же
команды с помощью которой передаются входящие сообщения, и которая
... не может быть передана в соединение находящееся в
BOUND_TX! В действительности, такие сообщения, называемые
delivery receipts некоторое время хранятся на SMSC и передаются в
первое же, авторизовавшееся с помощью bind_receiver, соединение
с тем же system_id. Таким образом, достаточно время от времени
открывать сессию с помощью bind_receiver и "снимать" delivery
receipt'ы и входящие сообщения, буде таковые найдутся, или просто сразу же
открывать две сессии. Понятно, что для сессий в состоянии BOUND_TRX
таких проблем не существует. Однако, в случаях больших загрузок
предпочтительней иметь отдельные сессии на прием и передачу (возможно, в
разных потоках исполнения -- threads) чтобы распараллелить эти операции.
Глава 2. Промежуточный итог 2
В данной главе мы обсудили процедуру авторизации поверх
сокетного соединения. Как мы видим, она не слишком сложна, хотя здесь есть
некоторые интересные моменты. Нам осталось обсудить команды передачи и
приема сообщений и мы вплотную приблизимся к кодированию. Оставайтесь с нами! P. S.
Кстати, еще раз напомним, что возникшие вопросы вы можете задать в форуме.
|