Прежде всего, несколько общих слов о самом протоколе SMPP (Short Message Peer to Peer). Протокол SMPP используется поверх TCP/IP (как и небезызвестный HTTP). Протокол является бинарным, в отличие, например, от того же самого HTTP, что делает невозможным тестирование подключения с помощью простейших текстовых клиентов, таких как telnet. Обычно этот протокол используется в режиме постоянного подключения (в отличие от большинства случаев с HTTP, когда клиент устанавливает соединение, совершает запрос, сервер ему отвечает и соединение закрывается). Постоянное подключение позволяет значительно повысить скорость передачи, т.к. не требуется каждый раз устанавливать соединение.
SMPP-клиент, минимальная версия
Я опишу минимальный набор действий, которые нужно совершить, чтобы отправить SMS по протоколу SMPP. Сразу оговорюсь, что здесь и в дальнейшем речь будет идти о протоколе SMPP v.3.4 (версия 3.4). Хотя на момент написания статьи существует более новая версия 5.0, на практике она никем не используется в силу различных причин.
Итак, что нужно сделать, чтобы отправить SMS:
1. Подключиться к SMPP-серверу (SMPP-шлюзу, SMPP-коннектору, SMS-центру). 2. Отправить серверу сообщение BIND_TRANSMITTER. 3. Дождаться от сервера сообщения BIND_TRANSMITTER_RESP. 4. Отправить SMS сообщением SUBMIT_SM. 5. Дождаться от сервера сообщения SUBMIT_SM_RESP. 6. Разорвать соединение.
Прошу заметить, это минимальный набор действий, который в большинстве случаев позволить отправить SMS. У клиента, построенного по такой схеме, имеется целый ряд недостатков, о которых мы поговорим чуть позднее. А пока я подробнее опишу действия каждого пункта.
1. Подключение к SMPP-серверу
Здесь идет речь о сетевом (сокетном) подключении через TCP/IP. Можно выразить то же самое словами "установить TCP/IP-соединение". На данном этапе достаточно иметь ip-адрес SMPP-сервера и порт, к которому нужно подключаться. Нужно помнить о том, что многие SMPP-сервера не позволят Вам подключиться без предварительного соглашения. Как правило, все они защищены файерволами, и для каждого конкретного подключения ip-адрес клиента должен быть разрешен в системе сетевой защиты SMPP-сервера. Я описал несколько вариантов выражений, используемых в литературе в качестве синонима словосочетания "SMPP-сервер". На самом деле, далеко не всегда сервер, к которому Вы подключаетесь, имеет право называться SMS-центром (далее SMSC). SMSC - это аппаратно-программный комплекс, установленный у мобильного оператора, входящий в его структуру и имеющий подключение к Signalling System Number 7 (SS7, C7, No 7, ОКС №7, общеканальная сигнализация №7). Как правило, большинство SMSC имеют также и SMPP-коннектор, позволяющий подключаться к ним по SMPP. Однако это не означает, что, подключаясь куда-либо по SMPP, Вы подключаетесь именно к SMSC - это справедливо лишь в ряде случаев. Призываю Вас не путать эти разные понятия. Я буду использовать термин SMPP-сервер, подразумевая под этим любую систему, допускающую работу с ней по протоколу SMPP.
2. Отправка PDU BIND_TRANSMITTER
Необходимо сразу сказать, что работа по протоколу SMPP состоит в обмене пакетами данных между клиентом и сервером в обоих направлениях. Эти пакеты данных в терминологии SMPP называются PDU (Protocol Data Unit), но также используется термин "SMPP сообщение" (SMPP message). В дальнейшем я буду называть их PDU, если по контексту будет требоваться уточнение. PDU - это набор байтов, имеющих четко определенную структуру. PDU состоит из обязательного заголовка (PDU header) и необязательного (в зависимости от типа PDU) тела (PDU body). Для каждой PDU структура тела описана в спецификации протокола отдельно, но структура заголовка всегда одинакова (она будет описана позднее). Вы спросите "А зачем отправлять BIND_TRANSMITTER? Почему бы не отправить сразу SUBMIT_SM - ведь у нас минимальный клиент?" Но даже в минимальном клиенте нужно отправлять BIND_TRANSMITTER, потому что для отправки сообщения нужно открыть сессию - и никак иначе. Если попытаться сразу отправить SUBMIT_SM, SMPP-сервер вернет ошибку. Сессия - это некое состояние, после установления которого можно посылать и принимать SMS. При открытии сессии происходит авторизация клиента, ему предоставляется соответствующий контекст и т.п. В пределах одного TCP/IP-соединения можно установить только одну сессию. При необходимости нескольких сессий одновременно (а такая необходимость возникает) для каждой сессии устанавливается и поддерживается отдельное TCP/IP-соединение. Вообще говоря, если "правильный" клиент должен сделать и закрытие сессии (отправив PDU UNBIND и дождавшись UNBIND_RESP), то минимальный может и не делать этого, поскольку его задача - отправить SMS с минимальными усилиями.
3. Ожидание PDU BIND_TRANSMITTER_RESP
До того, как придет эта PDU, сессию нельзя считать открытой, а потому никакие другие PDU отправлять не следует. Получив BIND_TRANSMITTER_RESP, нужно убедиться, что значение поля "статус" в заголовке равно 0, что означает отсутствие ошибок при выполнении команды. Опять же, только минимальный клиент может себе позволить не анализировать это поле, поскольку его ненулевое значение обычно связано с более-менее длительными проблемами (как правило, это ошибка авторизации, и нужно звонить и выяснять, почему прежний пароль не подходит). Более продвинутый клиент может попробовать отправить SMS по другим доступным маршрутам, отправить уведомление администратору системы, периодически повторяя попытки открыть сессию.
4. Отправка SMS с помощью PDU SUBMIT_SM
Вот мы и добрались до того, ради чего все, собственно, затевалось. Мы формируем тело PDU, которое включает в себя адрес получателя, адрес отправителя (да, в SMPP Вы можете задать адрес отправителя, и, если по пути с этим адресом никто ничего не сделает, получатель SMS увидит именно этот адрес), текст сообщения и множество других параметров. Затем мы дополняем PDU соответствующим заголовком и отправляем SMPP-серверу.
5. Ожидание PDU SUBMIT_SM_RESP
Этим сообщением сервер подтвердит факт принятия SMS в обработку. Это еще не означает, что SMS отправлена, и даже не означает, что она будет отправлена, но в большинстве нормальных ситуаций можно считать сообщение отправленным.
6. Разрыв соединения
Как я уже говорил, перед разрывом самого соединения надо закрыть сессию, отправив PDU UNBIND (и дождавшись UNBIND_RESP). Мы не делаем этого сейчас только потому, что мы - "минимальный" клиент. Отправка сообщения все равно произойдет (если SMPP-сервер правильно спроектирован), но таким образом мы можем создать серверу дополнительную работу, а они и так обычно весьма загружены.
Недостатки минимального клиента
Итак, наш клиент отправил сообщение. Чем же он так плох? Возможно, его нельзя назвать плохим, ведь он выполнил свою задачу. Однако задачи бывают разные, и для многих из них он уже не подойдет. Примеры таких задач: 1. Отправка большого количества сообщений. В этом случае "правильный" клиент воспользовался бы свойствами постоянного соединения, что резко увеличивает скорость работы. Кроме того, можно использовать асинхронный режим отправки PDU (отправка нескольких PDU подряд до получения ответа от сервера), что еще сильнее увеличит скорость. 2. Получение подтверждения о доставке. Факт отправки SMS еще не означает, что оно будет доставлено. Могут возникнуть технически проблемы по пути следования сообщения, абонент может быть вне зоны действия сети, телефон может быть выключен, а номер не использоваться. В любом из этих случаев сообщение не будет получено абонентом. Конечно, SMSC будет некоторое время пытаться доставить SMS, но у каждой SMS есть время жизни, по окончании которого эти попытки прекращаются. Это время обычно составляет от 24 до 72 часов. Но, тем не менее, может оказаться так, что спустя 6 часов, сообщение будет доставлено, потому что абонент включит свой мобильный телефон. Но "минимальный" клиент об этом не узнает, потому что он не запрашивал отчет о доставке и не пытался его получить (к тому же для сессии, установленной PDU BIND_TRANSMITTER, получения отчетов невозможно). 3. Прием входящих SMS. Частенько бывает так, что нужно не только отправлять, но и принимать сообщения. Для этого клиент должен быть готов принять и обработать PDU DELIVER_SM, которую пришлет ему сервер при появлении входящего сообщения.
У реальных клиентов часто стоят еще более сложные задачи. Это поддержание нескольких соединений, разбивка/склейка длинных сообщений, кодирование/декодирование SMS с разным типом кодировки, маршрутизация сообщений при использовании нескольких подключений к разным SMPP-серверам и т.д.
Автор статьи Алексей Соколов.
  |