Протокол SMPP: устранение неполадок и тестирование отправки SMS

Люди практически перестали использовать SMS для общения, но с точки зрения бизнеса это по-прежнему важный инструмент — для оповещений, авторизации, информирования о статусе заказов и во множестве других ситуаций. Сегодня рассмотрим протокол SMPP и его связь с SMS, а затем настроим свой сервер и интегрируемся с SMS API, чтобы отправить сообщение.

Взаимодействие мобильной сети с интернетом через SMPP

Протокол SMPP нужен для обмена сообщениями между веб-приложениями и мобильными абонентами по сети TCP/IP. Он не доставляет сообщения оператору связи самостоятельно, а служит лишь каналом передачи данных.

Основные элементы системы передачи SMS

  • SMS (Short Message Service) — стандарт телекоммуникаций для отправки коротких текстовых сообщений между мобильными телефонами и другими устройствами через сети мобильной связи.

  • SMSC (Short Message Service Center) — ключевой элемент инфраструктуры мобильной сети. Управляет маршрутизацией сообщения между сетями, отправкой, приёмом, хранением и доставкой SMS, включая уведомления о ней. Когда получатель временно недоступен, SMSC хранит сообщение и передаёт его в момент подключения устройства к сети.

Взаимосвязь SMS и SMPP

Источник

Хотя SMPP и SMS функционируют на разных уровнях, они тесно связаны. SMPP используется для передачи сообщений через серверы и сети к мобильным абонентам. И SMPP, и SMS зависят от SMSC, который управляет процессом передачи сообщений.

Применение SMPP

SMPP эффективен для обмена сообщениями между интернет-серверами и операторами мобильной связи. Для общения только между серверами чаще используют другие протоколы: HTTP, MQTT или AMQP, так как они предназначены для широкого спектра задач серверного взаимодействия и более оптимизированы для таких целей.

Проблемы при работе с SMPP

Работа с протоколом иногда вызывает проблемы, связанные с его техническими особенностями и инфраструктурными ограничениями.

  1. Проблемы с установлением и поддержанием соединения.

Соединение с SMSC прерывается или не устанавливается, особенно при нестабильном интернет-соединении или неверной конфигурации.

  1. Ошибки аутентификации.

При выполнении команды bind_transmitter, bind_receiver или bind_transceiver.

  1. Ограничения по скорости отправки сообщений (throttling).

Кодами ошибок, связанных с превышением лимитов скорости.

  1. Ошибки при обработке длинных сообщений.

SMS с длиной более 160 символов могут не доставляться или приходить по частям, которые не собираются в единое сообщение на устройстве получателя.

  1. Проблемы с кодировкой.

Сообщения приходят с неправильными символами или нечитаемым текстом.

  1. Проблемы с подтверждениями доставки (Delivery Receipts).

Приложение не получает подтверждения доставки сообщений или получает их с задержкой.

  1. Неправильная обработка сетевых ошибок.

Приложение зависает или теряет сообщения при возникновении проблем с сетью.

  1. Отсутствие управления потоками сообщений.

Приложение перегружается при одновременной отправке множества SMS.

  1. Проблемы с задержками доставки.

Сообщения доставляются с задержкой, или SMSC долго обрабатывает запросы на отправку.

  1. Несовместимость версий SMPP.

Ошибки взаимодействия с SMSC или другими системами.

  1. Таймауты при отправке сообщений.

Соединение с SMSC может «зависнуть», и сообщения не отправляются.

Но все эти проблемы можно диагностировать и исправить при разработке, а тестирование позволит выпустить стабильную версию.

Создание сервера express.js

Теперь создадим свою систему для отправки SMS через API-платформу МТС Exolve. Развернём базовый сервер на express. Все конфиденциальные данные для подключения будут храниться в файле .env: добавим в него пароль, логин, хост и порт. Сервер будет слушать 3000 порт, а по роуту http://localhost:3000/send-smsмы начнём отправлять запросы через Postman и посылать сообщения.

Также важно установить зависимости: dotenv, express, smpp.

В главный файл app.js добавляем код:

c03e8546925e8d93ebfa3e319f7a0e72.png

Сейчас у нас есть сервер на express, который можно запустить командой node app.js.

Подключение к SMPP

Далее создадим соединение с SMPP с помощью документации МТС Exolve. В файл smppConnection.js добавляем код:

const smpp = require("smpp");
require("dotenv").config();


let session;
let isBound = false; // Переменная для отслеживания статуса привязки
let isBindingInProgress = false; // Флаг для отслеживания процесса привязки
let bindTimeout; // Таймер для сообщения о проблемах с привязкой


const closeSession = (reason) => {
  console.log(reason);
  session.destroy(); // Принудительное закрытие сессии
  isBound = false; // Обновляем статус сессии
};


const connectSMPP = () => {
  console.log("Попытка подключения к SMPP серверу...");
  session = new smpp.Session({
    host: process.env.SMPP_HOST,
    port: process.env.SMPP_PORT,
  });


  session.on("connect", () => {
    console.log("СMPP сервер подключен. Попытка привязки...");
    isBindingInProgress = true; // Указываем, что процесс привязки начался
    // Устанавливаем таймер на 5 секунд для закрытия сессии при задержке привязки
    bindTimeout = setTimeout(() => {
      if (isBindingInProgress) {
        closeSession(
          "Привязка занимает больше 5 секунд. Закрытие сессии. Возможно, неверные данные или проблемы с сервером."
        );
      }
    }, 5000); // Тайм-аут на 5 секунд


    session.bind_transceiver(
      {
        system_id: process.env.SMPP_SYSTEM_ID,
        password: process.env.SMPP_PASSWORD,
      },
      (pdu) => {
        clearTimeout(bindTimeout); // Очищаем таймер, если PDU получен
        isBindingInProgress = false; // Привязка завершена


        if (pdu.command_status === 0) {
          isBound = true; // Успешная привязка
          console.log("Успешное подключение к серверу SMPP");
        }
      }
    );
  });


  session.on("close", () => {
    if (isBindingInProgress) {
      console.error(
        "Соединение SMPP закрыто во время привязки. Вероятно, неверные данные аутентификации."
      );
    } else {
      console.log("Соединение SMPP закрыто.");
    }
    isBound = false; // Соединение закрыто, сессия неактивна
  });


  session.on("error", (error) => {
    clearTimeout(bindTimeout); // Очищаем таймер при ошибке
    closeSession(`Ошибка соединения SMPP: ${error}`);
  });


  session.on("pdu", (pdu) => {
    console.log("Получен PDU:", pdu);
  });
};
const getSession = () => {
  if (!isBound) {
    console.error(
      "Ошибка: SMPP сессия не привязана. Проверьте параметры аутентификации."
    );
  }
  return session;
};


module.exports = { connectSMPP, getSession };

Этот код устанавливает соединение с SMPP. Обратите внимание, что на каждом шаге производится вывод в консоль — для отслеживания ошибок.

Отправка SMS

Заключительная часть кода отправляет сообщения.

Добавляем код в новый файл smsService.js.

const { getSession } = require("./smppConnection");


const sendSMS = (phoneNumber, message, sender) => {
  const session = getSession();


  if (!session) {
    console.error(
      "Сессия SMPP не подключена или не активна. Сообщение не будет отправлено."
    );
    return;
  }


  console.log(
    `Попытка отправить сообщение: "${message}" на номер: ${phoneNumber} от отправителя: ${sender}`
  );


  session.submit_sm(
    {
      source_addr: sender, // Номер отправителя
      destination_addr: phoneNumber, // Номер получателя
      short_message: message, // Текст сообщения
      source_addr_ton: 1, // Тип номера отправителя (1 для международного номера)
      source_addr_npi: 1, // План нумерации отправителя (1 для E.164)
      dest_addr_ton: 1, // Тип номера получателя (1 для международного номера)
      dest_addr_npi: 1, // План нумерации получателя (1 для E.164)
      registered_delivery: 1, // Запрос уведомления о доставке
      data_coding: 0x08, // Кодировка сообщения (0x08 для Unicode, 0x00 для GSM7)
    },
    (pdu) => {
      console.log("Получен ответ PDU на отправку сообщения:", pdu);
      if (pdu.command_status === 0) {
        console.log("Сообщение отправлено успешно");
      } else {
        console.error("Не удалось отправить сообщение", pdu.command_status);
      }
    }
  );
};


module.exports = { sendSMS };

Тестирование подключения

Запустим приложение командой node app.js.

4322521386b62bd4cb9ead6bef3e2727.png

При корректно введённых данных программа выведет сообщение: «Успешное подключение к серверу SMPP». Попробуем ввести заведомо ложный host или port.

Если port неправильный, увидим предупреждение: «Ошибка соединения SMPP: Error: getaddrinfo ENOTFOUND smpp.exolve.ru123213».

Соединение SMPP закрыто.

92cfaafa03efbdc697d824b016e9329d.png

Если ошибка в указании port, то:
Попытка подключения к SMPP серверу…

node:internal/errors:541
      throw error;
      ^

RangeError [ERR_SOCKET_BAD_PORT]: Port should be >= 0 and < 65536. Received type string ('277511').
    at lookupAndConnect (node:net:1298:5)
    at Socket.connect (node:net:1255:5)
    at Object.connect (node:net:238:17)
    at new Session (C:\work\SMPP\node_modules\smpp\lib\smpp.js:67:33)
    at connectSMPP (C:\work\SMPP\smppConnection.js:17:13)
    at Object. (C:\work\SMPP\app.js:8:1)
    at Module._compile (node:internal/modules/cjs/loader:1469:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)
    at Module.load (node:internal/modules/cjs/loader:1288:32)
    at Module._load (node:internal/modules/cjs/loader:1104:12) {
  code: 'ERR_SOCKET_BAD_PORT'
}

a225b3b6d2891428ef857ff6cc39df54.png

Если мы неправильно ввели system_id или password, то соединение не будет установлено, и через 5 секунд отобразится ошибка:

Попытка привязки…

Привязка занимает больше 5 секунд. Закрытие сессии. Возможно, неверные данные или проблемы с сервером.

Соединение SMPP закрыто во время привязки. Вероятно, неверные данные аутентификации.

e57b87d4a78b0349d1d4175a165efbb1.png

Тестирование отправки SMS

Удобнее всего тестировать через Postman. Отправим POST-запрос по API http://localhost:3000/send-sms. Тело запроса:  

{
  "phoneNumber": "Ваш номер телефона",
  "message": "Ваше сообщение",
  "sender": "Номер телефона Exolve"
}

d7f06fb4823d58daec68945dea2681f8.png

Если введём неправильные номера, консоль сразу предупредит об этом. Если ошибок нет, то мы получим сообщение на указанный номер.

Получаем сообщение

Получаем сообщение

Обращайте внимание на PDU при отлавливании ошибок.

bf2ab355f1cb5bf6eba1ef3024feaef9.png

В этих отчётах есть вся нужная информация.

Тщательное изучение и умение работать с консолью поможет выявить и решить даже самую низкоуровневую проблему при работе с SMPP. А такие сервисы, как МТС Exolve, позаботились о подробной документации для работы с этим протоколом.

© Habrahabr.ru