Начнем с того, что работодателем мне была поставлена задача — создать механизм по отправке смс-сообщений фиксированной длины с помощью сервиса, который предоставляется компанией Билайн.
После получения необходимых реквизитов от провайдера: таких как логин, пароль, сетевой адрес, номер порта и небольшого томика документации, стало понятно, что дело придется иметь с так называемым сетевым протоколом SMPP v 3.4.
Надо признаться, что до этого момента у меня не было опыта работы с каким-либо сетевым протоколом, и кроме языка 1С уровня программиста-внедренца, более никаким программным языком не владею.
ActiveХ: Winsock
Главная и основная задача была найти программные средства, которые бы позволили работать с сетевым протоколом. В 1С таких средств не оказалось, может быть я их просто не нашел, и после тщательных поисков возникла идея воспользоваться АктивХ компонентой предоставляемой компанией Microsoft — Winsock.
Из википедии… Windows Sockets API (WSA), название которого было укорочено до Winsock. Это техническая спецификация, которая определяет, как сетевое программное обеспечение Windows будет получать доступ к сетевым сервисам, в том числе, TCP/IP. Он определяет стандартный интерфейс между клиентским приложением (таким как FTP-клиент или веб-браузер) и внешним стеком протоколов TCP/IP. Он основывается на API модели сокетов Беркли, использующейся в BSD для установки соединения между программами.
Для установки и регистрации в ОС Windows необходмых файлов данной компоненты воспользовался советом и просто установил на компьютер пакет http://www.microsoft.com/ru-ru/softmicrosoft/VisualStudioExpress.aspx
После установки пакета (я установил версию visual basic 2012 express) появилась возможность разместить на форме winsock компоненту и использовать ее свойства и методы.
Рис. 1 Расположение компоненты
Рис. 2 Методы winsock
Первым шагом алгоритма будет процедура инициализации настроек и выполнение метода подключения
Процедура Иницилизация() Экспорт
мWinSocketActiveX = ПолучитьФорму("Форма").ЭлементыФормы.WinSocket;
//иницилизация настроек для подключения
мWinSocketActiveX.RemotePort = 3334;
мWinSocketActiveX.RemoteHost = "217.118.84.12";
ВыполнитьПодключение();
КонецПроцедуры // Иницилизация()
Процедура ВыполнитьПодключение()
Если мWinSocketActiveX.State = 0 Тогда
мWinSocketActiveX.Connect();
КонецЕсли;
КонецПроцедуры
После успешной установки подключения к серверу клиенту необходимо в течении 10 секунд отправить команду BIND_TRANSMITTER или BIND_TRANSCEIVER иначе соединение будет разорвано сервером. Поэтому в коде проверяем статус подключения, собираем и отправляем пакет — PDU (Protocol Data Units (Bind_Transceiver).
Процедура ОпроситьСоединение() Экспорт
Если мWinSocketActiveX.State = 7 Тогда
PDU = СобратьПакет_BIND_Transceiver();
мWinSocketActiveX.SendData(PDU);
Иначе //обработать другие состояния!!!
КонецЕсли;
КонецПроцедуры // УстановитьСоединение()
Для сборки PDU используем многомерный массив 1С COMSafeArray.
Функция СобратьПакет_BIND_Transceiver()
Матрица = Новый COMSafeArray("VT_UI1",37);
Матрица.SetValue(0,0);
Матрица.SetValue(1,0);
Матрица.SetValue(2,0);
Матрица.SetValue(3,37);
//код сокращен для этой статьи***
//***
Матрица.SetValue(32,0);
Матрица.SetValue(33,52);
Матрица.SetValue(34,1);
Матрица.SetValue(35,1);
Матрица.SetValue(36,0);
Возврат Матрица;
КонецФункции // СобратьПакет_BIND_Transceiver()
Клиент обязан отвечать на все пакеты отправленные сервером соответствующим resp пакетом в течение 1 минуты. Иначе соединение будет разорвано сервером без отсылки UNBIND.
После установки подключения и авторизации сервер будет отправлять ENQUIRE_LINK пакеты каждую минуту. На этот пакет клиент также обязан ответить в течение 1 минуты.
Методом DataArrival() принимаем и обрабатываем входящие пакеты:
Процедура WinSocketDataArrival(Элемент, bytesTotal)
ВходящийПакет = Неопределено;
мWinSocketActiveX.GetData(ВходящийПакет);
Если ТипЗнч(ВходящийПакет) = Тип("COMSafeArray") Тогда
ОбработатьВходящийПакет(ВходящийПакет);
КонецЕсли;
КонецПроцедуры
Процедура ОбработатьВходящийПакет(Пакет) Экспорт
//пришел пакет ENQUIRE_LINK
Если Пакет.GetValue(4) = 0 И Пакет.GetValue(7) = 21 Тогда
PDU = Фабрика_PDU_ENQUIRE_LINK_RESP(Пакет);
ОтправитьПакет(PDU);
Если мФлагОтправитьСМС Тогда
СобратьИОтправитьПакет_CMC();//отсюда отправялем смс-сообщение
мФлагОтправитьСМС = Ложь;
КонецЕсли;
КонецЕсли;
//пришел пакет bind_transceiver_resp
Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 9 Тогда
ОбработатьПакет_bind_transceiver_resp(Пакет);
КонецЕсли;
//пришел пакет submit_sm_resp
Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 4 Тогда
ОбработатьПакет_submit_sm_resp(Пакет);
КонецЕсли;
//пришел пакет Query_sm_resp
Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 3 Тогда
ОбработатьПакет_Query_sm_resp(Пакет);
КонецЕсли;
//пришел пакет UNBIND_resp
Если Пакет.GetValue(4) = 128 И Пакет.GetValue(7) = 6 Тогда
мWinSocketActiveX = Неопределено;
КонецЕсли;
КонецПроцедуры // ОбработатьВходящийПакет()
После того как клиент и сервер успешно обменялись пакетами ENQUIRE_LINK можно отправить текст смс-сообщения
Процедура СобратьИОтправитьПакет_CMC()
Перем PDU;
Если ЗаполнитьТаблицуЗначенийСМС() Тогда
НомерТел = мТабЗнДиспетчерСМС[0].НомерТелефона;
НомерДок = мТабЗнДиспетчерСМС[0].НомерДокумента;
ДатаДок = мТабЗнДиспетчерСМС[0].ДатаДокумента;
СтатусСМС = мТабЗнДиспетчерСМС[0].СтатусСМС;
ИдентификаторСМС = мТабЗнДиспетчерСМС[0].ИдентификаторСМС;
ТипДокумента = мТабЗнДиспетчерСМС[0].ЗаказПокупателя;
Если СтатусСМС = 0 Тогда
PDU = СобратьПакет_Submit_SM(НомерТел,НомерДок,ДатаДок,ТипДокумента);
СтрокаСообщения = Формат(ТекущаяДата(),"ДЛФ=DT")+" <= Отправляю СМС на номер: " +НомерТел+". Inf...";
Лог.ДобавитьСтроку(СтрокаСообщения);
ИначеЕсли СтатусСМС = 10 Тогда
PDU = СобратьПакет_Query_SM(ИдентификаторСМС);
СтрокаСообщения = Формат(ТекущаяДата(),"ДЛФ=DT")+" <= Запрашиваю статус СМС для номера: "+НомерТел + " . Inf...";
Лог.ДобавитьСтроку(СтрокаСообщения);
КонецЕсли;
Иначе
СтрокаСообщения = Формат(ТекущаяДата(),"ДЛФ=DT")+" <= Нет данных для отправки смс. Закрываю канал связи. Inf...";
Лог.ДобавитьСтроку(СтрокаСообщения);
PDU = СобратьПакет_UNBIND(); // отправлять больше нечего. Закрываем соединение;
КонецЕсли;
ОтправитьПакет(PDU);
КонецПроцедуры // СобратьИОтправитьПакет_CMC()
// <Описание функции>
//
// Параметры
// <Параметр1> - <Тип.Вид> - <описание параметра>
// <продолжение описания параметра>
// <Параметр2> - <Тип.Вид> - <описание параметра>
// <продолжение описания параметра>
//
// Возвращаемое значение:
// <Тип.Вид> - <описание возвращаемого значения>
//
Функция СобратьПакет_Submit_SM(НомерТелефона,НомерДокумента,ДатаДокумента,Объект)
Перем ИспользоватьРусский;
ИспользоватьРусский = Истина; //настройка
Если ТипЗнч(Объект) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
СообщениеТекстЛатиница = "Vash tovar po zakazu N "+НомерДокумента+" ot " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy")+" dostavlen";
СообщениеТекстРусский = "Ваш товар по заказу № "+НомерДокумента+" от " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy")+" доставлен";
ИначеЕсли ТипЗнч(Объект) = Тип("ДокументСсылка.АктПретензий") Тогда
СообщениеТекстЛатиница = "Vash tovar gotov k vydachi. Akt pretenzii N "+НомерДокумента+" ot " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy");
СообщениеТекстРусский = "Ваш товар готов к выдаче. Акт претензии № "+НомерДокумента+" от " + Формат(ДатаДокумента,"ДФ=dd.MM.yyyy");
КонецЕсли;
Если ИспользоватьРусский Тогда
СообщениеТекст = СообщениеТекстРусский;
МассивКодовРусскихБукв = ЗакодироватьРусскийТекст(СообщениеТекстРусский);
ДлинаСообщения = СтрДлина(СообщениеТекст)*2;
DataCod = 8;
Иначе
СообщениеТекст = СообщениеТекстЛатиница;
ДлинаСообщения = СтрДлина(СообщениеТекст);
DataCod = 0;
КонецЕсли;
ДлинаНомераТелефона = СтрДлина(НомерТелефона);
ДлинаПакета = 32+ДлинаНомераТелефона+11+ДлинаСообщения;
МатрицаДанных = Новый COMSafeArray("VT_UI1",ДлинаПакета-1);
//Заголовок
МатрицаДанных.SetValue(0, 0);
МатрицаДанных.SetValue(1, 0);
МатрицаДанных.SetValue(2, 0);
МатрицаДанных.SetValue(3, ДлинаПакета-1);
МатрицаДанных.SetValue(4, 0);
МатрицаДанных.SetValue(5, 0);
МатрицаДанных.SetValue(6, 0);
МатрицаДанных.SetValue(7, 4);
МатрицаДанных.SetValue(8, 0);
МатрицаДанных.SetValue(9, 0);
МатрицаДанных.SetValue(10, 0);
МатрицаДанных.SetValue(11, 0);
МатрицаДанных.SetValue(12, 0);
МатрицаДанных.SetValue(13, 0);
МатрицаДанных.SetValue(14, 0);
МатрицаДанных.SetValue(15, 2); //номер пакета
//тело
МатрицаДанных.SetValue(16, 0);
МатрицаДанных.SetValue(17, 5);
МатрицаДанных.SetValue(18, 1);
МатрицаДанных.SetValue(19, КодСимвола("k")); //K
МатрицаДанных.SetValue(20, КодСимвола("."));
МатрицаДанных.SetValue(21, КодСимвола("a")); //
МатрицаДанных.SetValue(22, КодСимвола("p")); //
МатрицаДанных.SetValue(23, КодСимвола("e")); //
МатрицаДанных.SetValue(24, КодСимвола("l"));//
МатрицаДанных.SetValue(25, КодСимвола("s"));
МатрицаДанных.SetValue(26, КодСимвола("i"));
МатрицаДанных.SetValue(27, КодСимвола("n")); //
МатрицаДанных.SetValue(28, 0);
МатрицаДанных.SetValue(29, 1);
МатрицаДанных.SetValue(30, 1);
Индекс = 31;
Для НомерСтроки = 1 По ДлинаНомераТелефона Цикл
МатрицаДанных.SetValue(Индекс,КодСимвола(НомерТелефона,НомерСтроки));
Индекс = Индекс+1;
КонецЦикла;
МатрицаДанных.SetValue(42, 0);
МатрицаДанных.SetValue(43, 0);
МатрицаДанных.SetValue(44, 0);
МатрицаДанных.SetValue(45, 0);
МатрицаДанных.SetValue(46, 0);
МатрицаДанных.SetValue(47, 0);
МатрицаДанных.SetValue(48, 1);
МатрицаДанных.SetValue(49, 1);
МатрицаДанных.SetValue(50, DataCod);//data coding
МатрицаДанных.SetValue(51, 1);
МатрицаДанных.SetValue(52, ДлинаСообщения);
Индекс = 53;
Если ИспользоватьРусский Тогда
Для НомерСтроки1 = 0 По ДлинаСообщения-1 Цикл
СимВ = МассивКодовРусскихБукв[НомерСтроки1];
МатрицаДанных.SetValue(Индекс,СимВ);
Индекс = Индекс+1;
КонецЦикла;
Иначе
Для НомерСтроки2 = 1 По ДлинаСообщения Цикл
ЗначениеСимвола = КодСимвола(СообщениеТекст,НомерСтроки2);
МатрицаДанных.SetValue(Индекс,ЗначениеСимвола);
Индекс = Индекс+1;
КонецЦикла;
КонецЕсли;
Возврат МатрицаДанных;
КонецФункции // СобратьПакет_Submit_SM()
Процедура ОтправитьПакет(PDU)
Если мWinSocketActiveX.State = 7 Тогда
мWinSocketActiveX.SendData(PDU);
КонецЕсли;
КонецПроцедуры // ОтправитьПакет()
В правилах хорошего тона будет считаться отправка UNBIND пакета, если канал связи вы больше не будете использовать.
Насчет применимости пока не знаю, но если встретятся подобные задачи вернусь к публикации. Плюс за иллюстрацию технологии ActiveХ: Winsock как сторонних объектов 1С 8. Обычно очень редко приходится иметь с ними дело. Чаще с внешними компоненками *.dll вызовом через COM
Доброй ночи!
Интересовался подобной возможностью, но везде говорилось, что будет списана оплата смс оповещений, с телефона пользователя, ну или корпаративного телефона.
А в данном случае, требуется оплата? Или через интернет просто уходит и все?
Спасибо!
(2) Tanis, Доброе время суток! В моем случае данный сервис есть платный. Организация заключила договор с компанией Билайн, перечисляем абонентку.
(1) kostyaomsk, Спасибо за плюсик. 🙂 Что касается области применения технологии winsock, то мне кажется, что можно на нем написать какую-нибудь аську для 1С-пользователей.
Спасибо за информацию очень детально разжевано, все разложено по полочкам. Автор так держать. Будет чем занятся на выходных
Нужно будет попробовать внедрить хотя бы Асю на 1С (вернее массовое сообщение). Видел подобную реализацию, но каким-то древним методом на 7.7 для информирования (не эта естественно технология).
(6) kostyaomsk, Для аськи эта технология хорошо подойдет. К тому же на надо будет шифровать данные, т.к. через winsock строка передается на ура без кодирования, в ANSI
На клюшках смс проще всего купить доступ к сервису рассылки сообщений и из клюшек в него пихать исходные данные и все
(8) CheBurator, К сожалению, передо мной не ставилась задача выбирать провайдера по доставке смс. Уверен, что есть другие провайдеры, у которых сервис более доступен. Билайн выбрали потому, что данный протокол обеспечивает пакетную рассылку смс, и главное — это то, что Билайн предоставляет статус по каждой доставленной смс.
Для УФ не прокатит, ибо ActiveX
(9) все поставщики рассылок предоставляют вам нормальный API, в котором обязательно будет и статус сообщения. Вот небольшой список:
Некоторые из них предоставляют бесплатные смс для разработчиков в целях тестирования
(10) JohnyDeath, 🙂 УФ — это не тупик, а всего лишь препятствие, которое можно обойти.
(11) JohnyDeath, Я не агитирую за Билайн и за протокол SMPP :). Почему? Ответил уже в этой ветке.
(12) можно узнать про ваш способ?
(14) JohnyDeath, Пожайлуйста, 🙂 Мне ничего не мешает написать отдельную конфигурацию для рассылки смс на обычных формах, а дальше создать процедуру для обмена между конфигурациями с УФ и конфигурацией СМС
(15) радикальненько )
Мир этому дому!
Полезная информация — взял себе на заметку. Автору спасибо!
Спасибо! Как раз искал нечто подобное!
Долгое время искал подобное для Мегафона.
Компонента имеется на англоязычных ресурсах, но она довольно древняя (2003 года)
и ее не удалось подружить с 1С.
В итоге сейчас использую PHP-скрипты (просто формируется файл PHP, запускаемый на сервере 1С).
Автору + за старания.
Вопрос — предложенная схема нормально работает с длинными SMS — они в итоге склеиваются у получателя?
(19) ig1082, В компании Билайн, предупредили, что текст смс не более 160 символов. Но полагаю, что это ограничение чисто условное. В документации по SMPP 3.4, в разделе submit_sm, можно найти описание параметра, который управляет длиной см-сообщения. Но лично в этом не практиковался
а что помешало использовать SMTP протокол отправки? у билайна есть…
есть ли возможность создание смс переписки в 1с через smpp,нет ли каких нить ограничений?
(22) марксист, Если я вас правильно понял, то вряд ли это получиться. В телефон вы все равно вставляете симку сотовых операторов. Вы можете переписываться используя технологию TCP/IP. Можете в 1С написать сервер и клиент на winsock. Протокол кодирования SMPP для этого не нужен. У вас просто получиться аська для 1С
(21) mmoozzgg, Полагаю, что нет такого сервиса отправки СМС через SMTP у Билайна
(24) есть, сам юзаю
Показать
плюс за интересную статью.
минус за правописание «товар готов к выдачи» 😉
клиенты наверное в шоке.. или только те, кто знает русский язык.
(26) progersan, За грамматику не судите строго. Текст сообщение ноу-хау юристов нашей организации :)))
(21) mmoozzgg,
Ничего не помешало. Просто поставили задачу таким образом и в придачу дали томик документации. Это был SMPP 🙂
(28) ну за статью winsock конечно плюс
Заключайте абонемент, и оператор будет безразлично какой объем вы отправите
Можете выложить полный код функции СобратьПакет_BIND_Transceiver()?
(15) Не, ну а чо…правильно. Нафига нам универсальность? Создадим кучу конфигураций каждую под определенные нужны и наладим между ними обмен.
(32) olegpim, в этом нет необходимости. Скоро доделаю библиотеку отдельную, которая будет отсылать смс сообщения из 1С намного проще. Библиотека основана на Jamma.SMPP. Правда пришлось её доработать под отправку сообщений на кирилице и отправку длинных СМС.
(34) Simpson, Может быть вы займетесь саморекламой в другом месте? Инфостарт, уверен, предоставит вам такую возможность, и все сообщество, с удовольствием, оценит по достоинству ваш потенциальный продукт.
(35) а это не самореклама, она мне ни к чему
Вот и до меня добралось SMPP, только мегафоновское и мануалом на 188 страниц. Срок — 2 дня. Поэтому автору — огромное спасибо за статью
(37) orehova123, Добрый день
Мы тоже заключили договор с мегафоном, вот только кроме IP адреса ничего не получили и тем более мануал (сказали больше ничего не дадут), скажите у Вас получилось по этой статье настроить отправку через мегафон?
А всё-таки, где можно взять полный текст СобратьПакет_BIND_Transceiver()
или где найти описание что именно там должно быть?
Чуть подробнее:
Пытаюсь настроить взаимодействие 1С и Naumen (Naumen SoftPhone).
Сделал:
Потом через обработку ожидания каждую секунду проверяю статус:
Получаю примерно такие результаты:
6
7
7
7
7
7
8
8
8
…
Т.е. соединение автоматически разрывается через некоторое время.
Что нужно послать что бы соединение сохранялось, и где про это можно почитать?
Если используете протокол SMPP v 3.4 ,то для поддержания соединение необходимо обмениваться респ.пакетами
Александр (chilyagin) привет. Дали задачу по реализации отправки СМС через Мегафон c SMPP 3.4 Пользуясь твоей наработкой устанавливаю связь -> обмен LINK пакетами идет и связь поддерживается. Скачать пока не могу. Потому изобретаю что то сам. Не могу разобраться в каком виде передается текст (русский). Реализовал кодирование в UCS2 (HEX на ACII + разбиение на байтовые блоки) но в каком виде их запихивать в пакет PDU не пойму. Подскажи если есть возможность.
(42) gremromchello, Добрый день, Роман! Winsock компонента обменивается данными через многомерный массив 1С COMSafeArray. В статье приведен пример процедуры построения такого многомерного массива. Соответствие кодирования информации (символов) можете поискать в интернете или в «прицепе» к данному сообщению. Также в статье найдете пример функции сборки пакета «СобратьПакет_Submit_SM». На этом примере вы сможете понять, как монтировать текст сообщения
(43) Спасибо. Вот только таблица символов у меня другая. Но при анализе пакета в wireshark на вид все ок.