Автоматизация бизнеса

Пользовательский поиск

понедельник, 7 мая 2012 г.

Как отправить SMS C#

SMS (Short Message Service) возможно отправить в двух форматах. Один из форматов это текстовый, и другой  PDU (Protocol Description Unit). Текстовый формат достаточно прост и из-за простоты у него есть достаточно много ограничении. Например, в текстовом режиме нет доступа к настройкам параметров сообщения, а также нет возможности отправлять сообщение русскими буквами. Самый большой минус текстового формата то, что не все оборудование поддерживают его. Учитывая все вышесказанные причины обратим наш взор на формат PDU.
PDU формат достаточно запутан, но при этом он дает возможность употребить все потенциалы SMS. PDU содержит не только сообщения, но также много мета-информации об отправителе, его SMS-сервис центре, штампе времени и т.д. 
Для отправки sms используют две основные кодировки: 7-битная и UCS2. Первая из кодировок используется для отправки ASCII символов. Данная кодировка дает возможность отправить 140 байт информации, но если ее преобразовать в 8-битный вид мы сможем отправить целых 160 ASCII символов. В кодировке UCS2 есть возможность отправить сообщение русскими буквами, каждый символ кодируется двумя байтами и поэтому можно отправить всего 70 символов.


Подробно о PDU

PDU это строка из шестнадцатеричных байтов, из которой можно получить все параметры sms
PDU строку, содержащую sms, можно изначально разделить на две части. Первая часть содержит информацию о СМС-центре, и вторая часть, которая содержит информацию о номере получателя/отправителя, текст сообщения, тип сообщения и т.д.
SMS в PDU режиме можно представить в виде формулы следующим образом

SMS=SCA+TPDU

SCA- содержит информацию о смс-центре.
TPDU (Transport Protocol Data Unit) - основная информация.

Для отправки сообщения необходимо получить PDU. 
Первым шагом составим SCA. 
SCA состоит из трех блоков
1 байт1 байтОт 0 до 6 байт
Длина всего блока SCAТип номера SMS-центраНомер SMS-центра


Длина всего блока SCA, это длина типа номера СМС центра + длина номера СМС центра.

Тип номера, это формат номера телефона SMS-центра. В большинстве международный формат, например +37494221122. Международному формату соответствует шестнадцатеричный байт 91h. Ниже посмотрим как получаем 91. Так как, тип номера SMS-центра 1 байт и 1 байт равен 8 битам, то



76543210
Всегда установлен в 1Тип номераИдентификация плана нумерации




Обратите внимание, что бит № 7 должны всегда быть установлен в 1
бит 6, 5 и 4  обозначает  Тип номера
бит 3, 2, 1, 0 обозначает Идентификация плана нумерации


Тип номера

Биты
6 5 4
Значение типа из битов (6, 5 и 4)
0 0 0Неизвестно. Эта функция используется, когда пользователь или сеть не имеет априорной информации о плане нумерации.
0 0 1Международный номер.
0 1 0Национальный номер. Префикс или номер выхода не включаются.
1 0 1Буквенное-цифровое, (код в соответствии с GSM TS 03,38 7-битный алфавит по умолчанию)
1 1 0Сокращенный номер
1 1 1Зарезервировано для расширений


Наиболее распространенные значения этого октета составляет 91h = (10010001) двоичный, что указывает на международный формат. Номер телефона в международном формате выглядит 37494221122 (где код страны 374). В национальном формате тот же телефонный номер будет выглядеть 094221122. Международный формат является наиболее распространенным.


В национальном формате номера телефона, выглядит следующим образом: 
Бит №76543210
ИмяВсегда установлен в 1Тип номераИдентификация плана нумерации 
Значение10000001


81h=(10000001) двоичный формат.


И так для отправки сообщения "Тип номера SMS-центра" выбираем или 91 или 81.


Номер SMS-центра

Для того, чтобы получить номер SMS-центра в нужном виде надо сделать несколько шагов.
  1. Из номера надо убрать все, кроме цифр.
  2. Если количество цифр нечетное, добавить в конце цифр букву "F".
  3. В каждой паре цифр переставить местами символы (цифры). 
Вот это как будет выглядеть на примере.
Номер SMS-центра +37493297111
Уберем "+" символ, поскольку надо оставить только цифры. Останется у нас номер 37493297111, количество цифр 11 значит надо добавить "F". Получится 37493297111F. 
И в конце переместим местами символы в номере - 7394237911F1.

В итоге у нас есть тип номера (91), и есть сам номер (7394237911F1) соответственно можно получить длину всего блока (91 73 94 23 79 11 F1)=7 получившихся байт в шестнадцатеричном виде. 
И так, как мы помним SCA=Длина всего блока SCA (07) + Тип номера SMS-центра (91) + Номер SMS-центра (37493297111F) получим 079137493297111F, это наш SCA.

Разбираем TPDU

Вот что из себя представляет TPDU.

TPDU = "PDU-Type" + "TP-MR" + "TP-DA" + "TP-PID" + "TP-DCS" + "TP-VP" + "TP-UDL" + "TP-UD"


  • PDU-Type – Тип сообщения. Если поставлено "01"  значит это исходящее сообщение.
  • TP- MR – (TP-Message-Reference) –  ставим TP-MR = "00"
  • TP- DA – (TP-Destination-Address) – Номер телефона получателя сообщения
  • TP- PID – (TP-Protocol ID) –  всегда равен "00"
  • TP- DCS – (TP-Data-Coding-Scheme) – указывает схему кодирования данных для поля TP-UD поле 
  • TP- VP — TP-Validity-Period — Срок действия сообщения 
  • TP-UDL — TP-User-Data-Length – длина сообщения.
  • TP- UD — TP-User-Data – текст SMS-сообщения, закодированный согласно полю TP-DCS
Как получить TP- DA Номер телефона получателя сообщения.

1 байт1 байтОт 0 до 6 байт
Длина номера получателяТип номера получателяНомер получателя

Тип номера получателя или международный формат (91) или национальный (81).
Номер получателя составляется также, как и выше составили номер SMS центра. 
Поле "Длина номера получателя" считается не как количество байт, а как количество цифр в номере без учета символа "F", и указываем шестнадцатеричном виде.

Вот как поле TP-DA будет выглядеть на примере.

Номер получателя +37494123456.
Убираем все кроме цифр, необходимо добавить "F" если количество цифр нечетное, у нас получится 37494123456F. После переставим символы в каждой паре 7394143254F6. 
И так длина будет равна 0B поскольку количество цифр 11 (7394143254F6).
TP-DA=0B917394143254F6.

TP-DCS -схема кодирования.


00: кодировка 7-бит (160 знаков, только латинские символы)
08: кодировка UCS2 -70 знаков.
Если первый полубайт поставить 1, то сообщение будет FLASH типа, со соответствующей схемой кодировки.

TP-VP - Срок действия сообщения.


Срок действия сообщения надо вычислять как указано в таблице

TP-VPЗначение срока действия
0 to 143(TP-VP + 1) * 5  минут  (то есть 5 минут интервалом до 12 часов)
144 to 16712 часов + ((TP-VP - 143) * 30 минут)
168 to 196(TP-VP - 166) * 1 день
197 to 255(TP-VP - 192) * 1 неделя

Например если значение данного поля равно AA а это равно 170, значит срок равен (170-166)*1 день= 4 дня.

TP-UDL — TP-User-Data-Length – длина сообщения.


Если сообщение закодирована UCS2, то каждый символ кодируется двумя байтами. Сообщение из 10 букв будет иметь длину 20 байт, шестнадцатеричной системе счисления 14.
Если сообщение закодирована в 7-битной кодировке, то указывается количество символов. Сообщение из 10 букв будет иметь длину 10 байт, шестнадцатеричной системе счисления 0A.

TP-User-Data – текст SMS-сообщения, закодированный согласно полю TP-DCS



Для кодирования символа ASCII используется 7 бит , а поскольку 1 байт равен целых 8 бит,  по этому 7-й бит всегда равен 0. Этот свободный бит будет использован для упаковки. 
Ниже приведена пошаговая инструкция:


1. Берем первый байт, берется семь бит первого данного байта, потом из семи битов второго символа самый младший 0-й бит переносится в старший разряд первого байта.
2.  Берем второй байт, от второго байта осталось 6 бит, это означает что есть еще место для двух битов, берем из третьего байта два младших бита 1-й и 0-й и переносим их в старшие разряды второго байта. Получаем 1-й и 0-й бит третьего байта и 6 бит второго байта.
3. Берем третий байт, от второго байта осталось 5 бит, место найдется для трех битов, берем из четвертого байта три младших бита 2-й, 1-й и 0-й и переносим их в старшие разряды третьего байта. Получаем 2-й ,1-й и 0-й бит четвертого байта и 5 бит третьего.
4. Продолжаем до конца тем же образом.


Написание сообщений в кодировке UCS2 необходимо брать символ, перекодировать ее в двухбайтовое представление и отправлять.


Как отправить SMS

Для отправки SMS можно воспользоваться программой Hyper Terminal, которая поставляется с Windows. Управление модемов осуществляется AT командами. Данные команды должны передаваться модему. Сначала настроить COM port, 
Bits per second - 9600
Data bits - 8
Parity - None
Stop bits - 1
Flow control - Hardware

Я использую Siemens A60 и  вышеуказанные настройки могут отличатся.

Перевод модема на PDU режим осуществляются командой AT+CMGF=0 модем даст ответ ОК если  режим поддерживается и переключен на PDU режим, состояния режима можно проверить командой AT+CMGF=? .
И, так для отправки даем команду AT+CMGS="длина TPDU в байтах" , если все в порядке модем ответит приглашающей кавычкой ">". После передаем остальную часть - весь PDU. Для подтверждения надо нажать ALT+Z, код данной комбинации в ASCII равняется 26, этот код мы потом употребим в программе для отправки sms.  Если все сделано правильно, то модем ответит +CMGS: "номер" .


Отправка SMS средствами C#

Ниже приведены методы преобразования телефонного номера и сообщения в PDU формат и обратное действие. 

Для преобразования телефонного номера получателя и SMS-центра можно воспользоваться вот такой функцией


 private string EncodeNumber(string Number)
        {
            string result = "";

            Number = Number.Replace("+", "");
            if ((Number.Length % 2) > 0)
                Number += "F";
            int i = 0;
            while (i < Number.Length)
            {
                result += Number[i + 1].ToString() + Number[i].ToString();
                i += 2;
            }
            return result;
        }

Нам остается преобразовать текст, и вот как это делается в C#.

String7To8 функция перекодирует ASCII символы.


public string String7To8(string str)
        {
            string result = "";
            ASCIIEncoding enc = new ASCIIEncoding();
            byte[] arr =  enc.GetBytes(str);
            int i = 1;
            while (i < arr.Length)
            {
                int j = arr.Length - 1;
                while (j >= i)
                {
                    byte firstBit = (arr[j] % 2 > 0) ? (byte)0x80 : (byte)0x00;
                    arr[j - 1] = (byte)((arr[j - 1] & 0x7f) | firstBit);
                    arr[j] = (byte)(arr[j] >> 1);
                    j--;
                }
                i++;
            }
            i = 0;
            while ((i < arr.Length) && (arr[i] != 0))
            {
                result += arr[i].ToString("X2");
                i++;
            }
            return result;
        }

Для кодировки UCS2  можно воспользоваться функцией StringToUCS2.


public string StringToUCS2(string str)
        {
            UnicodeEncoding ue = new UnicodeEncoding();
            byte[] ucs = ue.GetBytes(str);
            int i = 0;
            while (i < ucs.Length)
            {
                byte b = ucs[i + 1];
                ucs[i + 1] = ucs[i];
                ucs[i] = b;
                i += 2;
            }
            return BitConverter.ToString(ucs2).Replace("-", "");
        }


Для перекодировки из PDU  в нормальный вид номер абонента и SMS-центра надо воспользоваться функцией DecodeNumber.

private string DecodeNumber(string Number)
        {
            string result = "";
            int i = 0;
            while (i < Number.Length)
            {
                result += Number[i + 1].ToString() + Number[i].ToString();
                i += 2;
            }

            result = result.Replace("F", "");

            return result;
        }


Тема не столько трудная, на сколько запутанная благодаря формату PDU. Для этого представляю Демо версию программы для отправки SMS и его исходники.

В исходниках есть еще класс для  преобразования PDU в текст, так что экспериментируйте и делитесь!!!!
Несколько сайтов для рассылки смс

Программы и плагины для смс рассылок

SMS рассылка

Отправка SMS-сообщений в сети мобильных операторов по всему миру

Самые выгодные тарифы для рассылки смс по всему миру

8 комментариев:

  1. боже, какой изврат.
    Такое впечатление, что создатели этого формата долго курили чего не надо.
    И что самое поганое с этими СМС - необходимость работать с платным посредником.

    ОтветитьУдалить
    Ответы
    1. Изврат еще какой...............

      Удалить
    2. При разработке данного стандарта упор шел на уменьшение размера пакета. То есть приходилось выбирать - либо красиво, просто, но пакеты значительно увеличиваются в размерах и усложняется разработка оборудования, либо немного выносим мозг программерам, но пакет короткий, сложность разработки оборудования снижается. Как бы Вы поступили?

      Удалить
  2. А как можно задать вместо номера отправителя его "имя", ну что-то вроде "SMS SUBS" ?

    ОтветитьУдалить
    Ответы
    1. Если я правильно понял ты хочешь отправить смс номеру который записан в телефоне? Если так, то надо AT командами сперва получить номер из памяти сим или телефона.

      Удалить
  3. Отлично работает. Огромное спасибо за статью

    ОтветитьУдалить
  4. Дык я не понял отправка идет бесплатно от сервиса или нужно башлять?

    ОтветитьУдалить