Это моя вторая статья про разработку своего проекта. Тем, кто не читал предыдущую статейку: она про то, как из одного места (гугл таблицы) автоматически экспортировать данные в другое (ноушн).
Сегодня я расскажу, как я писал (и проектировал) библиотеку для того, чтобы сторонние приложения могли получать данные, отправляемые моим приложением. Всех заинтересовавшихся прошу под кат.
Часть 1. Проблема
Вкратце про проект. Есть устройство, которое подключается к смартфону. Есть мое приложение, внутри которого нейросеть распознает данные от устройства и выдает результат. И есть другие приложения, которые хотят получить этот самый результат.
Результат бывает нескольких видов: голые данные с устройства, обработанные данные с устройства, информация о состоянии устройства, информация о правах доступа приложения к данным (например, что пользователь отозвал права доступа к данным устройства). Нужно как-то передавать этот самый результат в другие приложения.
Отправка сообщений в Telegram при помощи python в 2 строки кода
Если вдруг я что-то неправильно поясню по своему коду — вот тут документация к моей библиотеке.
Часть 2. Планируем решение
Есть замечательный механизм — Broadcast’ы. Если вкратце — это сообщение от одного приложения другим приложениям. Можно отправить сразу всем, а можно — какому-то определенному.
Чтобы это дело отправлять и принимать, нужно:
- Как-то сделать из передаваемого объекта JSON
- Отправить Broadcast
- Принять Broadcast в другом приложении
- Восстановить передаваемый объект из JSON
У меня объекты достаточно маленькие. Кроме того, зачастую надо получить именно JSON: я сам написал стороннее приложение, чтобы оно отправляло на сервер сырые данные. Поэтому я выбрал именно «сделать из передаваемого объекта JSON». Возможно, потом я передумаю.
Часть 3. Пилим решение
Пункт 1 и пункт 4. В JSON, а потом обратно
Тут все просто. Есть библиотека Gson, которая чудесно подходит для наших нужд.
Чтобы сделать все круто, переопределим метод toString(). Ну и сделать fromString(), чтобы получить обратно наш объект.
class SecureData(val eeg1: Double?, val eeg2: Double?, date: Date) < override fun toString(): String < val gson = Gson() return gson.toJson(this) >companion object < fun fromString(model: String): SecureData < val gson = Gson() return gson.fromJson(model, SecureData::class.java) >> >
Пункт 2. Посылаем объект
Вот пример такого кода:
val intent = Intent() intent.action = BroadcastUtils.BROADCAST_GESTURE intent.putExtra(BroadcastUtils.EXTRA_GESTRE, it.toString()) sendBroadcast(intent)
Тут мы создаем intent, задаем его действие, кладем объект и отправляем как broadcast.
BroadcastUtils.BROADCAST_GESTURE — это штучка, по которой мы будем фильтровать поступающие broadcast’ы в другом приложении (нужно ли обрабатывать это или не нужно).
Чтобы отправить сообщение конкретному приложению, нужно еще дополнительно задать следующее:
Сделал Python программу для отслеживания курса валют
intent.component = ComponentName( PermissionsFetcher.REFACE_APP, «$.receivers.ActionsReceiver» )
PermissionsFetcher.REFACE_APP — это APPLICATION_ID моего приложения, а $.receivers.ActionsReceiver — путь до ресивера.
Пункт 3. Получаем объекты
Вот так мы регистрируем ресивер. Если вы регистрируете его, используя контекст приложения — он будет получать broadcast’ы, пока приложение не закрыто. Если используете контекст активити — пока она не закроется.
registerReceiver(GesturesReceiver(), IntentFilter(BroadcastUtils.BROADCAST_GESTURE))
А вот GesturesReceiver:
class GesturesReceiver : BroadcastReceiver() < override fun onReceive(context: Context, intent: Intent) < Timber.i(«Received gesture») val action = BroadcastUtils.reparseGestureIntent(intent) MainApp.actionSubject.onNext(action) >>
Тут я, как видите, получил интент, переделал его обратно в объект и отправил куда-то-там с помощью RxJava.
Часть 4. Заключение
Вы прочитали статью по проектированию приложений, которые должны взаимодействовать с другими приложениями. Надеюсь, этот опыт вам чем-то поможет.
Для пущего эффекта можно посмотреть исходники моей библиотеки и пример работы с ней и поставить звездочку на случай, если вам когда-нибудь это пригодится: github.com/reface-tech/CodeSpecialApp
- Анализ и проектирование систем
- Разработка мобильных приложений
- Разработка под Android
- Kotlin
- Развитие стартапа
Источник: habr.com
Как создать программу которая будет отправлять данные
Рассмотрим однонаправленную связь между клиентом TcpClient и сервером TcpListener, когда либо сервер посылает данные, а клиент получает, либо, наоборот, клиент отправляет данные, а сервер получает. По сути здесь рассмотриваются те же примеры, что и в случае с сокетами в прошлой статье, только с использованием TcpListener и TcpClient.
Отправка данных клиенту
Сначала рассмотрим ситуацию, когда сервер отправляет данные, а клиент только их получает. Так, определим для сервера следующий код:
using System.Net; using System.Net.Sockets; using System.Text; var tcpListener = new TcpListener(IPAddress.Any, 8888); try < tcpListener.Start(); // запускаем сервер Console.WriteLine(«Сервер запущен. Ожидание подключений. «); while (true) < // получаем подключение в виде TcpClient using var tcpClient = await tcpListener.AcceptTcpClientAsync(); // получаем объект NetworkStream для взаимодействия с клиентом var stream = tcpClient.GetStream(); // определяем данные для отправки — отправляем текущее время byte[] data = Encoding.UTF8.GetBytes(DateTime.Now.ToLongTimeString()); // отправляем данные await stream.WriteAsync(data); Console.WriteLine($»Клиенту отправлены данные»); > > finally
В качестве примера просто отправляем клиенту текущее время в формате hh:mm:ss. Для этого конвертируем строку в массив байтов и отправляем их с помощью метода stream.WriteAsync(). А на консоль сервера выводим диагностическое сообщение.
На стороне клиента определим следующий код:
using System.Net.Sockets; using System.Text; using TcpClient tcpClient = new TcpClient(); await tcpClient.ConnectAsync(«127.0.0.1», 8888); // буфер для считывания данных byte[] data = new byte[512]; // получаем NetworkStream для взаимодействия с сервером var stream = tcpClient.GetStream(); // получаем данные из потока int bytes = await stream.ReadAsync(data); // получаем отправленное время string time = Encoding.UTF8.GetString(data, 0, bytes); Console.WriteLine($»Текущее время: «);
На стороне клиента мы знаем, что сервер отправляет дату в виде строки, и для ее считывания определяем буфер — массив из 512 байтов. С помощью метода stream.ReadAsync() считываем данные из потока, конвертируем байты в строку и выводим ее на консоль.
Запустим сервер и клиент. При обращении к серверу клиент получит текущее время:
Текущее время: 20:16:49
А консоль сервера отобразит ip-адрес клиента:
Сервер запущен. Ожидание подключений. Клиенту 127.0.0.1:65060 отправлены данные
Получение данных от клиента
Теперь рассмотрим другой вид однонаправленной связи между клиентом и серверов, когда, наоборот, клиент отправляет данные, а сервер просто получает. Так, определим для сервера следующий код:
using System.Net; using System.Net.Sockets; using System.Text; var tcpListener = new TcpListener(IPAddress.Any, 8888); try < tcpListener.Start(); // запускаем сервер Console.WriteLine(«Сервер запущен. Ожидание подключений. «); while (true) < // получаем подключение в виде TcpClient using var tcpClient = await tcpListener.AcceptTcpClientAsync(); // получаем объект NetworkStream для взаимодействия с клиентом var stream = tcpClient.GetStream(); // определяем буфер для получения данных byte[] responseData = new byte[1024]; int bytes = 0; // количество считанных байтов var response = new StringBuilder(); // для склеивания данных в строку // считываем данные do < bytes = await stream.ReadAsync(responseData); response.Append(Encoding.UTF8.GetString(responseData, 0, bytes)); >while(bytes > 0); // выводим отправленные клиентом данные Console.WriteLine(response); > > catch (Exception ex) < Console.WriteLine(ex.Message); >finally < tcpListener.Stop(); // останавливаем сервер >
Здесь получаем у tcpClient поток NetworkStream и используем его для считывания данных от клиента. В частности, с помощью метода stream.ReadAsync() считываем данные из потока в массив байтов. В данном случае предполагаем, что данные будут представлять строку. И после получения из байтов строки выводим ее на консоль.
На клиенте определим простейший код для отправки некоторой строки:
В данном случае с помощью метода stream.WriteAsync() отправляем данные серверу. В качестве данных выступает простая строка.
Запустим сервер и клиент. После успешного подключения и отправки данных на консоли клиента мы увидим соответствующее сообщение:
А сервер получит от клиента сообщение и отобразит его на консоли:
Сервер запущен. Ожидание подключений. Hello METANIT.COM
Стратегии получения данных
Одна из наиболее сложных частей в клиент-серверном взаимодействии в tcp — это получение данных. И здесь нет однозначного решения, но есть ряд стратегий:
- Использование буфера фиксированной длины, когда мы точно знаем, какой именно объем данных будет послан
- Отправка в ответе информации о размере ответа, получив которую, нам будет проще считать нужное количество байтов
- Использование маркера окончания ответа, получив который, мы завершим считывание данных
Использование любой из этих стратегий подразумевает определение пусть и примитивного но протокола взаимодействия между клиентом и сервером, когда клиент и сервер в соответствии с едиными правилами формируют, отправляют и извлекают данные из потока.
Версия с фиксированным буфером довольно очевидная, поэтому рассмотрим две остальных стратегии.
Использование маркера окончания ответа
Определим следующий код сервера:
using System.Net; using System.Net.Sockets; using System.Text; var tcpListener = new TcpListener(IPAddress.Any, 8888); try < tcpListener.Start(); // запускаем сервер Console.WriteLine(«Сервер запущен. Ожидание подключений. «); while (true) < // получаем подключение в виде TcpClient using var tcpClient = await tcpListener.AcceptTcpClientAsync(); // получаем объект NetworkStream для взаимодействия с клиентом var stream = tcpClient.GetStream(); // буфер для входящих данных var buffer = new List(); int bytesRead = ‘n’; // считываем данные до конечного символа while((bytesRead = stream.ReadByte())!=’n’) < // добавляем в буфер buffer.Add((byte)bytesRead); >var message = Encoding.UTF8.GetString(buffer.ToArray()); Console.WriteLine($»Получено сообщение: «); > > finally < tcpListener.Stop(); // останавливаем сервер >
Здесь с помощью метода stream.ReadByte() считываем каждый байт из потока. Результатом метода является представление байта в виде int. Допустим, здесь в качестве маркера окончания сообщения будет выступать символ n или перевод строки, который представляет значение 10. И если встретился перевод строки, то заканчиваем чтение данных и конвертируем полученные данные в строку.
В этом случае клиент должен будет добавлять в конец сообщения символ n:
Хотя это в какой-то степени несколько примитивное упрощение, поскольку в данном случае мы ограничиваемся отправкой однострочного текста. Но в реальности логика определения конечного маркера может быть более сложной, особенно когда маркер представляет не одним байт/символ, а несколько, но общий принип будет тем же.
Установка размера сообщения
Определим следующий сервер:
using System.Net; using System.Net.Sockets; using System.Text; var tcpListener = new TcpListener(IPAddress.Any, 8888); try < tcpListener.Start(); // запускаем сервер Console.WriteLine(«Сервер запущен. Ожидание подключений. «); while (true) < // получаем подключение в виде TcpClient using var tcpClient = await tcpListener.AcceptTcpClientAsync(); // получаем объект NetworkStream для взаимодействия с клиентом var stream = tcpClient.GetStream(); // буфер для считывания размера данных byte[] sizeBuffer = new byte[4]; // сначала считываем размер данных await stream.ReadExactlyAsync(sizeBuffer, 0, sizeBuffer.Length); // узнаем размер и создаем соответствующий буфер int size = BitConverter.ToInt32(sizeBuffer, 0); // создаем соответствующий буфер byte[] data = new byte[size]; // считываем собственно данные int bytes = await stream.ReadAsync(data); var message = Encoding.UTF8.GetString(data, 0, bytes); Console.WriteLine($»Размер сообщения: байтов»); Console.WriteLine($»Сообщение: «); > > finally < tcpListener.Stop(); // останавливаем сервер >
В данном случае мы предполагаем, что размер будет представлять значение типа int — то есть значение в 4 байта. Соответственно для считывания размера создаем буфер из 4 байт и считываем его с помощью метода stream.ReadExactlyAsync , который считывает определенное количество байт из потока (в данном случае 4 байта):
await stream.ReadExactlyAsync(sizeBuffer, 0, sizeBuffer.Length);
Считав размер, мы можем конвертировать его в число int с помощью статического метода BitConverter.ToInt32() , определить буфер соответствующей длины и считать в него данные.
На стороне клиента определим следующий код:
Здесь происходит обратный процесс. Сначала получаем размер сообщения в массив байтов методом BitConverter.GetBytes() :
byte[] size = BitConverter.GetBytes(data.Length);
Отправляем размер в виде четырех байтов и затем отправляем сами данные:
await stream.WriteAsync(size); await stream.WriteAsync(data);
В итоге после отправки клиентом данных консоль сервера отобразит размер данных и сами данные:
Сервер запущен. Ожидание подключений. Размер сообщения: 17 байтов Сообщение: Hello METANIT.COM
Множественная отправка и получение
Выше клиент отправлял, а сервер получал только одно сообщение.
Но что, если отправляется множество сообщений, которые сервер должен получать по отдельности. В этом случае нам опять нужно определить какой-нибудь протокол, в соответствии с которым сервер может определить, когда завершается одной сообщение, а когда клиент вообще завершает взавимодействие. Рассмотрим небольшой пример. Пусть сервер будет иметь следующий код:
using System.Net; using System.Net.Sockets; using System.Text; var tcpListener = new TcpListener(IPAddress.Any, 8888); try < tcpListener.Start(); Console.WriteLine(«Сервер запущен. Ожидание подключений. «); while (true) < // получаем подключение в виде TcpClient using var tcpClient = await tcpListener.AcceptTcpClientAsync(); // получаем объект NetworkStream для взаимодействия с клиентом var stream = tcpClient.GetStream(); // буфер для входящих данных var buffer = new List(); int bytesRead = 10; while(true) < // считываем данные до конечного символа while ((bytesRead = stream.ReadByte()) != ‘n’) < // добавляем в буфер buffer.Add((byte)bytesRead); >var message = Encoding.UTF8.GetString(buffer.ToArray()); // если прислан маркер окончания взаимодействия, // выходим из цикла и завершаем взаимодействие с клиентом if (message == «END») break; Console.WriteLine($»Получено сообщение: «); buffer.Clear(); > > > finally
Итак, здесь наш протокол клиент-серверного взаимодействия состоит из двух правил. Во-первых, каждое отдельное сообщение должно заканчиваться переводом строки n. Во-вторых, когда клиент хочет завершить взаимодействие и отключиться от сервера, он посылает команду «END». Поэтому в бесконечном цикле обрабатываем все сообщения от клиента, а во вложенном цикле считываем по байту:
while(true) < // считываем данные до конечного символа while ((bytesRead = stream.ReadByte()) != ‘n’) < // добавляем в буфер buffer.Add((byte)bytesRead); >
Если пришла команда «END», выходит из бесконечного цикла:
var message = Encoding.UTF8.GetString(buffer.ToArray()); // если прислан маркер окончания взаимодействия, // выходим из цикла и завершаем взаимодействие с клиентом if (message == «END») break; Console.WriteLine($»Получено сообщение: «); buffer.Clear(); >
Для работы с этим сервером определим следующий клиент:
using System.Net.Sockets; using System.Text; using TcpClient tcpClient = new TcpClient(); await tcpClient.ConnectAsync(«127.0.0.1», 8888); // сообщения для отправки // сообщение завершается конечным символом — n, // который символизирует окончание сообщения var messages = new string[] < «Hello METANIT.COMn», «Hello Tcplistenern», «Bye METANIT.COMn», «ENDn» >; // получаем NetworkStream для взаимодействия с сервером var stream = tcpClient.GetStream(); foreach (var message in messages) < // считыванием строку в массив байт byte[] data = Encoding.UTF8.GetBytes(message); // отправляем данные await stream.WriteAsync(data); >Console.WriteLine(«Все сообщения отправлены»);
Здесь каждое отправляемое сообщение оканчивается терминальным символом n, кроме того, последнее сообщение представляет команду окончания взаимодействия «END». В итоге при подключении этого клиента сервер оторазит на консоли все присланные сообщения, кроме команды «END», которая завершит взаимодействие клиента и сервера:
Сервер запущен. Ожидание подключений. Получено сообщение: Hello METANIT.COM Получено сообщение: Hello Tcplistener Получено сообщение: Bye METANIT.COM
Источник: metanit.com
Отправка писем с помощью JavaScript
JavaScript – это язык программирования, который можно использовать как для интерфейсной, так и для внутренней разработки. Когда JavaScript упоминается в контексте отправки электронных писем, Node.js – это первое, что приходит на ум. И сегодня мы разберем, как использовать JS для отправки электронных писем из приложения, у которого нет сервера.
FAQ: Могу ли я отправлять электронные письма с JS или нет?
Вы не можете отправлять электронные письма, используя только код JavaScript, из-за отсутствия поддержки серверных соединений. Для этого вам понадобится серверный язык, который общается с SMTP-сервером. Вы можете использовать JS вместе с серверным скриптом, который будет отправлять электронные письма из браузера на основе ваших запросов.
Почему вы можете захотеть отправлять электронные письма с помощью JS
Традиционно серверная часть обычного приложения отвечает за отправку электронных писем. Вам нужно будет настроить сервер с использованием внутренней технологии. Клиентская сторона отправляет запрос на сервер, который создает электронное письмо и отправляет его на SMTP-сервер.
Итак, почему кто-то может пойти другим путем и отправлять электронные письма прямо со стороны клиента с помощью JavaScript? Такой подход весьма полезен для создания контактных форм или других видов взаимодействия с пользователем в веб-приложениях, что позволяет вашему приложению отправлять электронную почту без обновления страницы, с которой взаимодействует пользователь. Кроме того, вам не нужно возиться с кодированием сервера. Это веский аргумент, если ваше веб-приложение использует отправку электронной почты только для контактных форм. Ниже вы найдете несколько вариантов того, как заставить ваше приложение отправлять электронные письма со стороны клиента.
mailto: для отправки формы данных
Поскольку вы не можете отправить электронное письмо напрямую с помощью JS, вы можете указать браузеру открыть для этого почтовый клиент по умолчанию. Технически метод mailto: не отправляет электронную почту прямо из браузера, но может выполнять следующую работу:
FirstName: Email:
Когда вы запустите код в браузере, вы увидите следующее:
После отправки данных браузер открывает почтовый клиент по умолчанию. В нашем случае это Gmail.
Метод mailto: является довольно простым решением для реализации , но он имеет некоторые специфические недостатки:
- Вы не можете контролировать макет данных, поскольку данные отправляются в форме, отправленной браузером.
- mailto: не защищает ваш адрес электронной почты от спам-ботов. Некоторое время назад это можно было смягчить, построив ссылку в JS. В наши дни все больше и больше ботов запускают JS и не полагаются на HTML, отображаемый только сервером.
SmtpJS.com – отправка писем из JavaScript
SmtpJS – это бесплатная библиотека, которую вы можете использовать для отправки писем из JavaScript. Все, что вам нужно, – это SMTP-сервер и несколько манипуляций, чтобы все было сделано. Мы будем использовать Mailtrap.io в качестве сервера, потому что это действенное решение для тестирования электронной почты. Ниже приведен порядок действий, которому вы должны следовать:
- Создайте HTML-файл (например, test.html) со следующим скриптом:
- Создайте кнопку, которая будет запускать функцию JavaScript.
- Напишите функцию JS для отправки писем через SmtpJS.com.
- Запустите test.html в браузере и отправьте письмо
Недостатком приведенного выше примера является то, что ваше имя пользователя и пароль видны в клиентском скрипте. Это можно исправить, если использовать параметр шифрования, предоставляемый SmtpJS. Нажмите кнопку «Зашифровать свои учетные данные SMTP» и заполните необходимые поля.
После этого нажмите “Сгенерировать токен безопасности” и затем используйте его в своей функции JS вместо настроек SMTP-сервера, как показано ниже:
SecureToken : «»
Источник: uproger.com