« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
    Популярное
Веб-сервисы как вариант основы информационной инфраструктуры предприятия

Журнал регистрации

Комплексные числа в .NET

Управление сетями IBM

Чего мы ждем от C# 4.0

Расчет координаты точки после уменьшения изображения

Описание функций C (Си) / C++ - getpid

Функция EqualRgn

JavaScript - полезные функции часть 6

Взлом компонентов Delphi




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 167
Пользователей: 0

Статьи:: Интернет технологии :: Java2ME :: Использование J2ME. Часть 2



отправить ссылку другу версия для печати  Обсудить на форуме

Использование J2ME. Часть 2



Мобильный телефон как средство доступа в Internet

Использование J2ME. Часть 2

Обзор

В этой части статьи разговор пойдет о коммуникационных возможностях конфигурации CLDC вообще и профиля MIDP в частности. Будет дан небольшой обзор GCF и пример ее использования в реальном приложении.

 

Generic Connection Framework

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


Рисунок 1.

Как Вы можете видеть, классов действительно немного и самое интересное, что их действительно хватает для работы с любыми типами соединений по любым протоколам.

И так, соединение создается с помощью вызова статического метода класса Connector:


Connector.open("<protocol>:<address><parameters>");

Синтаксис строки должен соответствовать RFC2396 [2]. <protocol> - протокол, с помощью которого будет выполнена попытка установить соединение, <address> - адрес ресурса, формат адреса зависит от используемого протокола, <parameters> - параметры соединения. Предполагается, что все это будет работать примерно так:

  1. при вызове open(), будет произведен разбор строки и определение запрашиваемого протокола;
  2. будет выполнена попытка создать экземпляр класса, который реализует запрашиваемый протокол;
  3. если такой протокол найден, ему будут переданы поля <address> и <parameters>.

Примеры создания соединений [1] (на уровне CLDC отсутствует реализация каких-либо протоколов - реализация выполняется на уровне профиля):

HTTP
Connector.open("http://www.foo.com");
Sockets
Connector.open("socket://129.144.111.222:9000");
Communication ports
Connector.open("comm:0;baudrate=9600");
Datagrams
Connector.open("datagram://:1234");
Files
Connector.open("file:/foo.dat");

Ниже будет дано очень краткое описание классов GCF, более полное описание Вы можете найти в спецификации [1]:

Connection
Самый простой класс представляющий соединение, которое можно только открыть и закрыть.

InputConnection
Представляет соединение, с помощью которого можно принимать данные.

OutputConnection
Представляет соединение, с помощью которого можно передавать данные.

StreamConnection
Представляет соединение, с помощью которого можно и передавать и принимать данные.

ContentConnection
К двусторонней передаче данных добавляет возможность получение некоторой мета-информации о соединении (для HTTP протокола, например, можно получить тип используемой кодировки).

StreamConnectionNotifier
Данный интерфейс позволяет ждать установление соединения.

DatagramConnection
Этот интерфейс предоставляет доступ к протоколам датаграммного обмена данными (например UDP в стеке протоколов TCP/IP). Для работы с такими типами соединений существует дополнительный класс Datagram, который инкапсулирует в себе буфер с данными и адрес. Отметим, что данный интерфейс позволяет работать как в "клиентском", так и в "серверном" режиме, т.е. по сути позволяет использовать "серверные сокеты" или "слушатели". Еще раз хочется повторить замечание, которое уже было сделано в предыдущей статье: профиль MIDP обязан поддерживать только протокол HTTP, но может поддерживать и датаграммные протоколы. В случае поддержки таких протоколов это должно быть реализовано через GFC. Такая дискриминация по отношению к отличным от HTTP протоколам связана с тем, что не все беспроводные сети базируются на стеках протоколов, способных поддерживать датаграмные соединение или соединения с помощью сокетов. Реализация же HTTP может быть сделана поверх любого доступного в данной сети транспортного протокола.

Проектируем коммуникационную часть

Теперь, используя знания полученные в предыдущей главе нам не составит труда реализовать связку "клитент-сервер", используя push модель. Для справки, push модель в отношении коммуникационной задачи, это когда сервер "заталкивает" (pushing) событие в клиента (существует еще pull модель - клиент сам "вытягивает" (pulling) событие с сервера). В общем виде push модель с помощью sequence диаграммы представлена на рис. 2.

Рисунок 2
Рисунок 2.

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

Протокол передачи сообщений

Немного терминологии. Мобильным клиентом или просто клиентом мы будем называть проектируемое нами программное обеспечение (ПО) для мобильного устройства. Пользователем будем называть человека, который пользуется этим ПО. Сервером будем называть ПО обеспечивающее взаимодействие клиентов с системой обмена сообщениями (собственно сам сервер и реализует эту систему). Чтобы грамотно спроектировать протокол обмена сообщениями сначала нужно определиться с требованиями к нему, а также описать основные сценарии его работы (прецеденты или use case).

Требования:

  • возможность авторизованного входа и выхода их системы;
  • возможность передачи сообщений от одного мобильного клиента другому;
  • по запросу снабжать клиента списком других пользователей системы с возможностью задания критерия отбора;
  • возможность извещения клиента об ошибочном сообщении (адресат недоступен);

Прецеденты:

  1. Вход в систему: клиент посылает сообщение серверу содержащее имя и пароль, сервер проверяет правильность имени и пароля в соответствии со своей внутренней базой и посылает клиенту либо подтверждение о входе, либо отказ, клиент добавляется во внутреннюю таблицу он-лайн клиентов;
     
  2. Посылка сообщения: клиент посылает сообщение серверу содержащее имя получателя и текст сообщения, сервер проверяет доступность адресата и пересылает ему сообщение, если адресат недоступен, сервер посылает сообщение об ошибке отправителю;
     
  3. Запрос списка клиентов: клиент посылает сообщение с запросом списка, сервер формирует список в соответствии с критерием ипосылает список клиенту;
     
  4. Выход клиента из системы: клиент посылает сообщение серверу с запросом о выходе из системы, сервер модифицирует внутреннюю таблицу об он-лайн клиентах;
     
  5. Выход сервера из системы: сервер рассылает всем доступным клиентам уведомление о своем выходе из системы, все клиенты переходят в отсоединенное состояние.
     

Реализация

Диаграмма общих для клиента и сервера классов, относящихся к протоколу передачи данных, представлена на рис. 3.

Рисунок 3
Рисунок 3.

Message - класс, инкапсулирующий всю семантику сообщения, MobileProtocol - интерфейс задающий методы, которые должен реализовывать класс, который хочет выступать в роли протокола кодирования/декодирования сообщений в/из массива байт, MessageReceivedListener - интерфейс, который должен реализовывать класс, который хочет быть уведомленным о приходе нового сообщения, более подробно на нем мы остановимся немного познее.

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

  1. Клиент и сервер используют один и тотже класс, реализующий протокол;
  2. Классы разные, но используют один и тотже формат кодирования;

Мы остановимся на первом варианте - он более честный. Правда здесь сразу возникает небольшая проблема - понятно, что для кодирования объекта класса Message в массив байт (или поток, кому как нравиться) в J2SE удобно использовать сериализацию, но механизм сериализации отсутствует в J2ME, отсутствуют классы типа ObjectOutputStream. Зато в J2ME есть DataOutputStream, его и будем использовать.

С учетом всех вышеописанных замечаний реализация класса SimpleMobileProtocol выглядит следующим образом:

public class SimpleMobileProtocol implements MobileProtocol
{
 public SimpleMobileProtocol()
 {
 }

 public Message decodeMessage(byte[] data) throws IOException
 {
  ByteArrayInputStream bais = new ByteArrayInputStream(data);
  DataInputStream dis = new DataInputStream(bais);

  Message message = new Message();
  message.setType(dis.readInt());
  message.setSender(dis.readUTF());
  message.setRecipient(dis.readUTF());
  message.setPassword(dis.readUTF());
  message.setInfo(dis.readUTF());

  Vector users = new Vector();
  int size = dis.readInt();

  for (int i = 0; i < size; i++)
  {
   users.addElement(dis.readUTF());
  }

  message.setUsers(users);

  return message;
 }

 public byte[] encodeMessage(Message message) throws IOException
 {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  DataOutputStream das = new DataOutputStream(baos);

  das.writeInt(message.getType());
  das.writeUTF(message.getSender());
  das.writeUTF(message.getRecipient());
  das.writeUTF(message.getPassword());
  das.writeUTF(message.getInfo());

  Vector users = message.getUsers();

  das.writeInt(users.size());
  for (int i = 0; i < users.size(); i++)
  {
   das.writeUTF((String)users.elementAt(i));
  }

  return baos.toByteArray();
 }
}


Я думаю каких-то особенных комментариев сдесь не нужно делать, отмечу только, что вместо метода DataOutputStream.writeChars(String) используется метод writeUTF(String). Это связано с тем, что второй записывает в поток информацию о длине строки, что необходимо для ее успешного декодирования. Вектор строк сохраняется в виде <кол-во_элементов>[строка1[строка2[строка3..]..]..]

Серверный и клиентский коннекторы

Теперь начнем использовать только что описанный протокол. Заметьте, что класс SimpleMobileProtocol является частью всего протокола и отвечает только за кодирование/декодирование сообщений, еще к протоколу относится некоторые соглашения и требования, описанные выше, именно их мы и попытаемя дальше реализовать.

Для сервера и клиента все вопросы обмена сообщениями вынесены в отдельные классы - клиентский и серверный коннекторы (см. рис 4).

Рисунок 4
Рисунок 4.

Оба класса наследуются от класса Thread (хотя на диаграмме это один и тотже класс, на самом деле в J2SE и J2ME эти классы различаются) и аггрегируют интерфейс MessageReceivedListener. Классы имеют метод для посылки сообщения sendMessage(Message) и умеют уведомлять о приходе нового сообщения посредством вызова метода MessageReceivedListener.messageReceived(Message).

На примере процедуры входа пользователя в систему, все это хозяйство работает следующим образом (см. рис.5):

Рисунок 5
Рисунок 5. (нажмите на рисунок для увеличения)

  1. создание и инициализация сервером и клиентом своих коннекторов. Обычно эти шаги разнесены по времени - сначала запускают сервер, потом клиента
  2. -"-
  3. -"-
  4. -"-
  5. клиент посылает запрос на вход в систему (TYPE_LOGIN), передавая серверу свое имя и пароль
  6. клиентский коннектор преобразует сообщение в массив байт для отправки серверу
  7. посылка пакета серверу по протоколу UDP
  8. серверный коннектор декодирует сообщение из массива принятых байтов
  9. уведомление сервера о получении нового сообщения. На этом шаге на самом деле сервер ничего не делает, этот вызов отладочный и используется для отображения сервером принимаемых сообщений на консоль
  10. коннектор проверяет права пользователя. При использовании SimpleUserDatabase проверяется только наличие пользователя в базе и совпадение принятого пароля с паролем из базы
  11. в случае удачной проверки прав пользователя серверный коннектор посылает клиентскому коннектору сообщение об удачном входе в систему
  12. клиентский коннектор уведомляет MIDlet о приему нового сообщения

Ниже приведен код клиентского коннектора с комментариями.

public class ClientConnector extends Thread
{
 /** слушатель, который хочет получать
     уведомление о приходе нового сообщения */
 private MessageReceivedListener listener = null;
 /** серверный сокет для получения входящих датаграмм */
 private javax.microedition.io.DatagramConnection 
                          clientConnection = null;
 /** имя хоста сервера */
 private String serverHost;
 /** номер порта, на котором слушает сервер */
 private int serverPort;
 /** номер порта, на котором должен слушать клиент */
 private int clientPort;
 /** протокол, для кодирования/декодирования сообщений */
 private MobileProtocol protocol;

 public ClientConnector(String serverHost,
                        int serverPort,int clientPort,
                        MessageReceivedListener listener,
                        MobileProtocol protocol) 
                                    throws IOException
 { 
  this.serverHost = serverHost;
  this.serverPort = serverPort;
  this.clientPort = clientPort;
  this.listener = listener;
  this.protocol = protocol;
/* создание листенера входящих датаграм от сервера */
  clientConnection = 
           (javax.microedition.io.DatagramConnection)
  Connector.open("datagram://:" + 
                   Integer.toString(clientPort));
 }

/**
 * установка класса, который должен быть 
 * уведомлен о приходе нового сообщения
 */
 public void addMessageReceivedListener
          (MessageReceivedListener listener)
 {
  this.listener = listener;
 }

 public void run()
 {
  Datagram datagram;
  try
  {
 /* зацикливаем нить, пока есть
    кому получать входящие сообщения */
   while (listener != null)
   {
    /* создаем датаграму */
    datagram =clientConnection.newDatagram(
              clientConnection.getNominalLength());
                /* ждем входящего сообщения */
    clientConnection.receive(datagram);
    if (listener == null)
    {
     return;
    }
    else
    {
/* расшифровываем сообщение с помощью установленного
      протокола и уведомляем об этом получателя*/
     listener.messageReceived(
        protocol.decodeMessage(datagram.getData()));
    }
   }
  } 
  catch (Exception e)
  {
   e.printStackTrace();
   return;
  } 
  finally
  {
   if (clientConnection != null)
   {
    try
    {
     clientConnection.close();
    }
    catch (Exception e)
    {
     e.printStackTrace();
    }
   }
  }
 }

/**
 * метод для отправки сообщений серверу
 */
 public void sendMessage(Message message) throws IOException
 {
 /* кодируем сообщние */
  byte[] data = protocol.encodeMessage(message);
 /*  создаем соединение с сервером */
  DatagramConnection serverConnection =
  (javax.microedition.io.DatagramConnection)Connector.open(
       "datagram://" + serverHost + 
       ":"+ Integer.toString(serverPort));
 /*  создаем датаграму наполненную полезной информацией */
  Datagram datagram = 
     serverConnection.newDatagram(data, data.length);
        /* отправляем датаграму и закрываем соединение*/
  serverConnection.send(datagram);
  serverConnection.close();
 }
}


Описание серверного коннектора и работы серверного приложения целиком будет дано в одной из последующих глав. Также в последующих главах будет рассмотрено

  • пакет javax.microedition.rms - служит для долговременного хранения какой-либо информации в постоянной памяти мобильного устройства
  • пакет javax.microedition.lcdui - служит для создания интерфейса пользователя
  • пакет javax.microedition.midlet - служит для создания самого MIDP приложения

Ресурсы

  1. Connected, Limited Device Configuration. Specification Version 1.0. (http://www.sun.com/software/communitysource/j2me/cldc/)
  2. Uniform Resource Identifiers (URI): Generic Syntax (http://www.ietf.org/rfc/rfc2396.txt)
  3. Mobile Information Device Profile (JSR-37). JCP Specification Version 1.0a. (http://www.sun.com/software/communitysource/midp/)



Рубрика: Java2ME




Вышел MySQL 5.1.30, первый стабильный рели....

MySQL

После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:


Подробнее... | Рубрика: MySQL | Добавлено: 28.11.2008

Тестирование параллельных программ.

Тестирование

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


Подробнее... | Рубрика: Тестирование | Добавлено: 28.11.2008

Архитектура AMD64 (EM64T).

Архитектура AMD

Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.


Подробнее... | Рубрика: Архитектура AMD | Добавлено: 27.11.2008

Остальные статьи:

Платформа 2009. Определяя будущее
Windows Vista Bridge Sample Library - упра...
Оптимизация 64-битных программ
Подгрузка через AJAX HTML-кода, содержащег...
Обзор нового релиза самой мощной Ajax библ...
Firebug 1.3 и 1.4 alpha — что нового и инт...
Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия