Каталог решений - Пример реализации отправки sms через протокол SMPP v 3.4

Пример реализации отправки sms через протокол SMPP v 3.4

Пример реализации отправки sms через протокол SMPP v 3.4

В наличии

В этой статье публикуется пример реализации сервиса по отправке смс-сообщений через протокол SMPP v3.4 из программы семейства 1С:Предприятие 8x.

Категория:

Описание

Начнем с того, что работодателем мне была поставлена задача — создать механизм по отправке смс-сообщений фиксированной длины с помощью сервиса, который предоставляется компанией Билайн.

После получения необходимых реквизитов от провайдера: таких как логин, пароль, сетевой адрес, номер порта и небольшого томика документации, стало понятно, что дело придется иметь с так называемым сетевым протоколом 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

Metod 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 пакета, если канал связи вы больше не будете использовать.

has been added to your cart:
Оформление заказа