Мобильная архивация (Передача зашифрованных SMS в j2me)

Сжимаем SMS на J2ME!

Размер SMS-сообщения сильно ограничен, что правда, то правда. Ограничен он 160 символами для СМСок состоящих только из латиницы и 70 символами для тех, в тексте которых, содержатся символы национальных языков, например, русского. Причем достаточно всего одной русской буквы в сообщении, что бы его максимальный размер уменьшился более чем вдвое. Давай попробуем разобраться, с чем это связанно, ликвидировать этот ужасный недостаток и вообще немного расширить возможный объем SMS. Кодирование текста

Еще со школы нам известно, что компьютеры и прочие железяки не понимают никаких букв, а представляют всю информацию исключительно в виде набора ноликов и единичек. Соответствие между символами и их цифровым представлением называется кодировкой. В мире существует огромное множество кодировок. Самые распространенные среди них условно можно разделить на три класса: восьмибитные, семибитные, и шестнадцатибитные.

В восьмибитных кодировках для представления одного символа требуется 8 бит или 1 байт, из чего следует, что такой кодировкой можно охватить 256 символов.

В семибитных на кодирование символа отводится уже 7 бит, а количество возможных символов равно 128.

В шестнадцатибитных же кодировках символ кодируется аж 2 байтами, при этом количество охватываемых символов - 65536. Внушительный объем кодировки позволяет вместить в себя символы всех существующих национальных алфавитов одновременно, в отличие от, скажем, восьмибитовых кодировок, которые вмещают только латиницу и еще один национальный алфавит. Представителем шестнадцатибитной кодировки является unicode.

Для кодирования текста SMS используется семибитная кодировка, в случае если в текст состоит только из символов латинского алфавита. А поскольку максимальный объем SMS-сообщения в соответствии со стандартами составляет 1120 бит, то легко подсчитать максимальное количество символов. Оно равно 1120/7 = 160.

Как только в тексте сообщения появляется символ, скажем, кириллицы, кодировка меняется с семибитной на Unicode с ее двумя байтами на символ. Максимальный объем СМСки при этом становится равным 1120/16 = 70.

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

Долой Unicode

Попробуем придумать свою собственную кодировку, при использовании которой влезало бы больше текста в одно сообщение. Сформулируем требования к ней: кодировка должна позволять использовать символы латиницы и кириллицы, цифры от 0 до 9, а также – символы: ".,!?-_"/:@". Максимальный объем сообщения, представленного нашей кодировкой должен быть не менее 160 символов, а лучше более.

За основу нашей кодировки возьмем шестибитное кодирование. Оно позволяет закодировать 64 символа и в отведенные нам стандартом 1120 бит поместится 186 таких символов.

Разместить в таблице из 64 элементов символы двух алфавитов, знаки препинания и цифры нам не удастся, они просто все не влезут. Поэтому нужно сделать так, чтобы одному коду могло сразу несколько символов, переключение между которым осуществлялось бы с помощью других специальных. Подобная система очень напоминает клавиатуру, где на каждой клавише расположено несколько символов (разного регистра или языка), и выбор осуществляется нажатием клавиши Shift.

Итак, в первых 32 элементах будем хранить символы кириллицы от "а" до "я". Одну букву кириллицы я намеренно исключил. Благо правила русского языка позволяют мне это сделать. Какую? Догадайся сам (подсказка: эта буква ни разу не встречается на страницах этого журнала).

Так же в первых 26 элементах будем хранить символы латиницы от "a" до "z". Т.е. код 2 будет у нас одновременно соответствовать и кириллической букве "б" и латинской букве "b".

Знаки препинания мы поместим с 32 позиции в таблице по 41. Цифры от 0 до 9 самое просто тоже будет поместить в начало нашей таблицы и присвоить им коды от 0 до 9, что, в общем, логично. Теперь коды от 0 до 9 соответствуют 3 символам (кириллица, латиница и цифры). Как же определить какой конкретно символ из трех выбрать? Для этого мы будем использовать символы-модификаторы. В основной таблице у нас осталось 22 пустых ячейки. В часть из них мы и поместим модификаторы.

Нам потребуются следующие модификаторы: переключатель "кириллица/латиница", переключатель "цифры/не цифры", переключатель "заглавные/строчные" и переключатель "следующая заглавная".

Для того, что бы понять, как работают модификаторы, давай закодируем такое сообщение: "Привет Lexa мой НОМЕР - 128. Пока", и посмотрим, что выйдет.

[следующая заглавная]привет [кириллица/латиница][следующая заглавная]lexa[кириллица/латиница] мой [заглавные/строчные]номер - [цифры/не цифры]128.[цифры/не цифры] п[заглавные/строчные]ока


Аналогия с клавишей Shift на лицо. Первое упоминание модификатора - это нажатие клавиши, второе напоминание - это ее отпускание. На начальном этапе модификаторы установлены в положение "строчные кириллические буквы".

Из общего ряда выделяется модификатор "следующая заглавная", он не требует отключения. Преимущество использования его, а не модификатора "строчные/заглавные” очевидно и равно 6 битам.

В Unicode такое сообщение занимало бы 33*2 = 66 байт. В нашей кодировке оно занимает 41*6/8=31 байт. Здорово, сжали сообщение больше чем в два раза, но мы не будем останавливаться на достигнутом. Мы задействовали только 46 кодов и у нас в запасе еще 18. Эти 18 кодов позволяют нам использовать для 3 символов не шестибитное, а четырехбитное кодирование. На рисунке показано за счет чего осуществляется переход к 4 битам, и почему таких символов может быть только 3.

Каким же символам присвоить такие короткие коды? Ответ очевиден: наиболее часто встречающимся в текстах на русском языке – пробелу (о котором, кстати, мы вообще забыли) и буквам "о" и "е".

Проведя несколько экспериментов, легко увидеть, насколько большой выигрыш мы получим за счет использования всего лишь трех четырехбитных кодов.

Подготовка

Для того чтобы осуществить подобное кодирование SMS-сообщений у себя на телефоне потребуется немного разобраться в программировании на J2ME, поддерживающимся на большинстве современных моделей. А для того, чтобы в нем разобраться необходим некоторый софт. Компилятор, среда и эмулятор. Компилятор – сделает из текста программы готовый мидлет, среда нужна для того, чтобы не париться и не изучать разные ключи компилятора, а также, чтобы не искать текстовый редактор. Эмулятор же нужен для тестирования и запуска полученного в результате компиляции приложения.

Смело устанавливай с диска К сожалению, не все можно протестировать на эмуляторе, особенно если это универсальный эмулятор. Поэтому пользоваться телефоном для тестирования придется. В реальной мобиле некоторые вещи могут работать немного иначе. Мне, например, так и не удалось осуществить отправку SMS с одного эмулятора на другой. Зато отправка сообщения с эмулятор на обычный телефон прошла на ура. Правда, последующие двое суток я получал эту СМСку на свой телефон каждый час. Видимо, на шлюзе, через который происходила отправка, случился сбой :).

Попытки реализации

Вооружившись всем необходимым для программирования и тестирования софтом, наконец, можно попробовать осуществить нашу идею. Для этого заходим в директорию с WTK и из поддиректории bin запускаем ktoolbar.exe. В появившемся окне выбираем пункт "New Project" и создаем новый проект, sms_test, с таким же названием класса. В следующем окошке не читая, кликаем "ok". На данной стадии настройки нас совершенно не интересуют.

Проект создан и теперь можешь приступать к написанию мидлета. Исходники твоей программки будут храниться в директории apps/sms_test/src. Полный код уже готового мидлета для изучения ты можешь найти на диске, здесь же я рассмотрю только некоторые вопросы.

Итак, цикл разработки приложения для твоей мобилы состоит из двух фаз:

  1. Написание кода мидлета, его компиляция и отладка на эмуляторе
  2. Загрузка мидлета в телефон и тестирование его на телефоне

Для того чтобы отправить СМС из своей программы нужно использовать Wireless Messaging API. Набор очень удобных и понятных классов:

  • MessageConnection – определяет операции для посылки и получения сообщений.
  • MessageListener - позволяет мидлету получать уведомления о входящих сообщениях
  • Message - основной интерфейс для представления сообщений, из которого наследуются два следующих класса.
  • TextMessage - класс текстового сообщения.
  • BinaryMessage - класс бинарного сообщения.

Следующий код осуществляет отправку SMS-сообщения c помощью этого API:

try{
String addr="sms://+1234567890";
MessageConnection conn=(MessageConnection) Connector.open(addr);
TextMessage msg=(TextMessage)conn.newMessage(MessageConnection.TEXT_MESSAGE);
msg.setPayloadText("Hello World!");
conn.send(msg);
 
}
catch(Exception e){}
 

Как видишь, здесь все очень просто:

  1. создаем соединение
  2. создаем сообщение
  3. отправляем сообщение
  4. закрываем соединение

В случае с отправкой кодированных по нашему методу сообщений, следует использовать класс BinaryMessage. Соответственно код преобразуется следующим образом:

byte[] bin_msg;
try{
String addr="sms://+1234567890:5151";
 
MessageConnection conn=(MessageConnection) Connector.open(addr);
BinaryMessage msg=(BinaryMessage)conn.newMessage(MessageConnection.BINARY_MESSAGE);
msg.setPayloadData(bin_msg);
conn.send(msg);
}
catch(Exception e){}
 
 

Обрати внимание на то, что в строке адреса появилось дополнение в виде ":5151". Это номер порта, на который следует отправлять СМСку. Дело в том, что существует два вида SMS-сообщений, в которых присутствует номер порта, и в которых его в помине нет. Сообщения первого типа принимаются стандартным ПО телефона. Сообщения второго типа, в свою очередь, должны обрабатываться соответствующими мидлетами настроенными на получение сообщений из данного порта. Если в момент поступления сообщения такой мидлет не запущен, то сообщение передается стандартному ПО мобилы.

К примеру, получать все сообщения пришедшие на 5151 порт можно с помощью следующего простого кода:

try{
String addr="sms://:5151";
MessageConnection conn=(MessageConnection) Connector.open(addr);
Message msg=null;
while(!ex){
msg= conn.receive();
if(msg instanceof TextMessage){
TextMessage txt_msg=(TextMessage)msg;
String text= txt_msg.getPayloadText();
txt_msg.setPayloadText("Received: "+ text);
conn.send(txt_msg);
}
}
}
catch(Exception e){}


Тут ты можешь столкнуться с небольшой проблемой. Мидлет предназначенный для получения СМСок с определенного порта будет получать их только в то время когда он запущен. В случае если СМСка придет, когда мидлет не запущен, она перенаправится стандартному ПО телефона. Решением данной проблемы является использование технологии Push Registry, которая позволяет установить соответствие между мидлетом и некоторым портом. При поступлении информации в зарегистрированной специальным способом порт твой мидлет автоматически загрузится.

Таким образом, получается некоторое подобие сервера. Для того, что бы связать определенный порт с мидлетом, следует добавить в jad-файл строчку вроде этой:

MIDlet-Push-1: sms://:5151, sms_test, *

Грубо говоря, в этой строке оговорено, что при поступлении сообщений типа sms на 5151 порт, необходимо активизировать мидлет sms_test и передать ему эти данные. Далее мидлет должен проводить декодирование и отображать сообщение в читабельном виде (с этой, достаточно сложной, но очень интересной проблемой предстоит разобраться тебе самому). Посмотреть на уже реализованное приложение, которое принимает, получает, кодирует и декодирует сообщения по описанному выше принципу можно на диске.

Взгляд в прошлое

К сожалению, технология Push Registry поддерживается только в новых телефонах соответствующих стандарту MIDP версии 2.0. В более старых моделях поддерживающих версию 1.0 реализовать отправку и получение СМСок на порт с которым проассоциирован конкретный мидлет невозможно. А отправка закодированного сообщения на стандартное ПО телефонов не имеет смысла, поскольку текст в этом случае будет нечитаемым.

Кроме того, нигде не оговаривается, как должен активизироваться мидлет при поступлении очередной СМСки на связанный с ним порт. Так, например, на телефонах компании Siemens 65 серии в таких ситуациях просто появляется звездочка в левом нижнем углу экрана, без какого либо проигрывания мелодии или включения виброзвонка. Согласись, это не очень удобно (хотя, наверное, можно самому реализовать сигнал в мидлете).

Еще одной большой проблемой является тот факт, что заявления производителей о соответствии MIDP 2.0 еще ни о чем не говорят. Это очень напоминает ситуацию сложившуюся не так давно на рынке браузеров, когда там царили Internet Explorer и Netscape Navigator. Оба браузера поддерживали JavaScript и HTML, но оба делали это по-разному и имели разную объектную модель, в связи с чем разработчику приходилось делать фактически разные версии сайтов для разных браузеров.

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

INFO

Метод numberOfSegments класса MessageConnection позволяет узнать, на сколько сегментов будет разбито сообщение во время отправки.


Исходник примера:sms_test.rar


Источник:Хакер №075,.
Автор: Филипп Коряка.




Наши соцсети

Подписаться Facebook Подписаться Вконтакте Подписаться Twitter Подписаться Google Подписаться Telegram

Популярное

Ссылки

Новости [1] [2] [3]... Android/ iOS/ J2ME[1] [2] [3]) Android / Архив

Рейтинг@Mail.ru Яндекс.Метрика
MobiLab.ru © 2005-2018
При использовании материалов сайта ссылка на www.mobilab.ru обязательна