Программирование КПК и смартфонов на .NET Compact Framework — страница 32 из 41

Рис. 11.10. Сайт CodeProject, посвященный играм для .NET Compact Framework

Глава 12Связь

Инфракрасное соединение

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

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

IrDAClient
, входящего в библиотеку классов .NET Compact Framework.

История и теория

Основанная в 1993 году как некоммерческая организация, Ассоциация инфракрасной передачи данных (Infrared Data Association, или сокращенно IrDA) является международной ассоциацией (www.irda.org), создающей и продвигающей стандарты инфракрасной связи, позволяющие пользователям соединять устройства для передачи данных. Стандарты Infrared Data Association поддерживают огромное число устройств. На данный момент существует несколько версий технологии IrDA, которые различаются скоростью передачи данных.

Протокол IrDA позволяет соединяться с другим устройством без проводов при помощи ИК-излучения. Порт IrDA позволяет устанавливать связь на расстоянии до 1-2 метров. Интерфейс IrDA предполагает малую мощность потребления, что позволяет создавать недорогую продукцию.

Класс IrDAClient

Практически все устройства под управлением Windows Mobile имеют встроенные инфракрасные порты. Библиотека .NET Compact Framework имеет в своем составе классы, позволяющие работать с инфракрасной связью.

Инфракрасная связь осуществляется между двумя устройствами по принципу «сервер-клиент». Устройство, работающее как сервер, предлагает другому компьютеру установить связь для передачи данных через инфракрасный порт. Для осуществления передачи необходимо передать идентификатор устройства и имя устройства. Клиент ждет вызова необходимой службы и откликается на ее запрос. В результате между двумя компьютерами устанавливается связь

За инфракрасное соединение отвечает специальный класс

IrDAClient
, который может выступать и в роли сервера, и в роли клиента. Данный класс входит в библиотеку
System.Net.IrDA.dll
. Таким образом, при использовании класса
IrDAClient
необходимо добавить в проект ссылку на указанную библиотеку.

Для чтения и передачи данных используется метод

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

1. Создать новый экземпляр класса

IrDAClient
.

2. Получить список доступных устройств с помощью метода

IrDAClient.DiscoverDevices
. Можно ограничить количество опрашиваемых устройств при помощи параметра
maxDevices
. Метод
DiscoverDevices
возвращает массив объектов
IrDADeviceInfo
.

3. Нужно исследовать каждый объект

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

4. Если подобное устройство найдено, то при помощи метода

IrDAClient.Connect
производится соединение. При этом необходимо указать имя службы

Создание программы для работы с ИК-связью

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

IrDA_CS
. На форме надо разместить три кнопки, список и строку состояния.

Кнопка

butFindDevs
предназначена для поиска устройств, кнопка
butSend
— для отправки текстового сообщения, а кнопка
butReceive
служит для приема сообщения. В списке
listBox1
будет отображаться информация об обнаруженных устройствах, а в строке состояния будут отображаться сообщения о производимых операциях. Для передачи данных и работы с файлами нам необходимо импортировать несколько пространств имен, как это показано в листинге 12.1.

Листинг 12.1

Imports System.Net

Imports System.IO

Imports System.Net.Sockets

Для работы с инфракрасной связью необходимо подключить к проекту класс

IrDAClient
. Для этого выполним команду меню
Project►Add Reference
и в диалоговом окне выберем пункт
System.Net.IrDa
.

Теперь нужно объявить переменные на уровне класса, как показано в листинге 12.2

Листинг 12.2

private IrDAListener irListen;

private IrDAClient irClient;

private IrDAEndPoint irEndP;

private IrDADeviceInfo[] irDevices;


string fileSend;

string fileReceive;

string irServiceName;


int buffersize;

В конструкторе формы надо создать экземпляр класса

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

Листинг 12.3

public Form1() {

 InitializeComponent();

 irClient = new IrDAClient();


 // Файлы, предназначенные для отправки и приема

 fileSend = ".\\My Documents\\send.txt";

 fileReceive = ".\\My Documents\\receive.txt";

 // Задаем имя для службы IrDA

 // Это может быть любое слово

 // Другие устройства для примера должны использовать это же

 // слово

 irServiceName = "IrDAFtp";


 // Устанавливаем максимальный размер буфера для передаваемого

 // файла

 buffersize = 256;


 // Делаем недоступными кнопки отправки и посылки сообщений

 // до тех пор, пока не будут обнаружены устройства

 butSend.Enabled = false;

 butReceive.Enabled = false;

}

Обнаружение устройств

Теперь надо написать код для кнопки

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

Листинг 12.4

private void butFindDevs_Click(object sender, EventArgs e) {

 // Ищем доступные устройства с инфракрасной связью

 // и помещаем их в список

 // Поиск не более трех доступных устройств

 irDevices = irClient.DiscoverDevices(2);


 // Если устройства не найдены, то выводим сообщение

 if (irDevices.Length == 0) {

  MessageBox.Show("Устройства с ИК-портами не обнаружены!");

  return;

 }


 // Перечисляем массив IrDADeviceInfo

 // и выводим информацию о каждом устройстве в список

 string device;

 int ID;

 listBox1.Items.Clear();

 foreach (IrDADeviceInfo irDevice in irDevices) {

  ID = BitConverter.ToInt32(irDevice.DeviceID, 0);

  device =

   ID.ToString() + " " + irDevice.DeviceName + " " + irDevice.CharacterSet +

   " " + irDevice.Hints;

  listBox1.Items.Add(device);

 }


 listBox1.SelectedIndex = 0;

 if (irDevices.Length > 0)

  statusBar1.Text = irDevices.Length.ToString() + " устройств(а)";


 // Делаем доступными кнопки для отправки и посылки сообщения

 butSend.Enabled = true;

 butReceive.Enabled = true;

}

Передача данных

Код для отправки и посылки файлов приведен в листинге 12.5.

Листинг 12.5

private void butSend_Click(object sender, EventArgs e) {

 // Открываем файл для отправки и получаем его поток

 Stream fileStream;

 try {

  fileStream = new FileStream(fileSend, FileMode.Open);

 } catch (Exception exFile) {

  MessageBox.Show("Не могу открыть " + exFile.ToString());

  return;

 }


 // Создаем IrDA-клиент с установленным именем службы.

 // которое должно совпадать с именем службы на другом

 // IrDA-клиенте

 try {

  irClient = new IrDAClient(irServiceName);

 } catch (SocketException exS) {

  MessageBox.Show("Ошибка сокета: " + exS.Message +

   " - Вы щелкнули на кнопке Получить на другом устройстве?");

  return;

 }


 // Получим поток

 Stream baseStream = irClient.GetStream();


 // Получим размер отправляемого файла

 // и запишем это значение в поток

 byte[] length = BitConverter.GetBytes((int)fileStream.Length);

 baseStream.Write(length, 0, length.Length);


 // Создаем буфер для чтения файла

 byte[] buffer = new byte[buffersize];


 // Показываем число отправленных байт

 int fileLength = (int)fileStream.Length;

 statusBar1.Text = "Отправлено " + fileLength + " байт";


 // Читаем файловый поток в базовом потоке

 while (fileLength > 0) {

  int numRead = fileStream.Read(buffer, 0, buffer.Length);

  baseStream.Write(buffer, 0, numRead);

  fileLength -= numRead;

 }


 fileStream.Close();

 baseStream.Close();

 irClient.Close();

 statusBar1.Text = "Файл отправлен";

}


private void butReceive_Click(object sender, EventArgs e) {

 // Создаем поток для записи файла

 Stream writeStream;

 try {

  writeStream = new FileStream(fileReceive, FileMode.OpenOrCreate);

 } catch (Exception) {

  MessageBox.Show("Не могу открыть "+ fileReceive + " для записи");

  return;

 }


 // Создаем соединение с помощью класса IrDAEndPoint

 // для выбранного устройства из списка

 // Начинаем прослушку входящих сообщений

 // из устройства с объектом IrDAListener

 try {

  int i = listBox1.SelectedIndex;

  irEndP = new IrDAEndPoint(irDevices[i].DeviceID, irServiceName);

  irListen = new IrDAListener(irEndP);

  irListen.Start();

 } catch (SocketException exSoc) {

  MessageBox.Show("Не могу прослушивать на службе " + irServiceName + ": " +

   exSoc.ErrorCode);

 }


 // Показываем прослушивание выбранного устройства

 statusBar1.Text = "Прослушка " + listBox1.SelectedItem.ToString();


 // Создаем соединение

 // для службы, обнаруженной прослушкой

 IrDAClient irClient;

 try {

  irClient = irListen.AcceptIrDAClient();

 } catch (SocketException exp) {

  MessageBox.Show("Не могу принять сокет "+ exp.ErrorCode);

  return;

 }


 // Показываем, идет ли передача файла

 if (irListen.Pending() == true)

  statusBar1.Text = "Передача из " + irClient.RemoteMachineName;

 else

  statusBar1.Text = "Нет передачи из " + irClient.RemoteMachineName;


 // Получим поток из клиента

 Stream baseStream = irClient.GetStream();

 int numToRead;

 // Создаем буфер для чтения файла

 byte[] buffer = new byte[buffersize];

 // Читаем поток данных, который содержит

 // данные из передающего устройства

 numToRead = 4;

 while (numToRead > 0) {

  int numRead = baseStream.Read(buffer, 0, numToRead);

  numToRead -= numRead;

 }


 // Получим размер буфера для показа

 // числа байт для записи в файл

 numToRead = BitConverter.ToInt32(buffer, 0);

 statusBar1.Text = "Записываем "+ numToRead + " байт";

 // Записываем поток в файл до тех пор,

 // пока не будут прочитаны все байты

 while (numToRead > 0) {

  int numRead = baseStream.Read(buffer, 0, buffer.Length);

  numToRead -= numRead;

  writeStream.Write(buffer, 0, numRead);

 }

 // Сообщаем, что файл получен

 statusBar1.Text = "Файл получен";

 baseStream.Close();

 writeStream.Close();

 irListen.Stop();

 irClient.Close();

}

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

send.txt
с любым содержанием. Затем нужно повернуть друг к другу инфракрасные датчики двух устройств и на первом устройстве нажать кнопку
Искать
. Если поиск завершился успешно, то в списке отобразится имя второго устройства.

Затем на втором устройстве надо нажать кнопку

Принять
, а на первом устройстве нажать кнопку
Отправить
. В результате ваших действий текст сообщения из файла
send.txt
должен быть передан на другое устройство и сохранен в файле
receive.txt
.

К сожалению, данный пример нельзя тестировать на эмуляторе. Для проведения эксперимента вам необходимо иметь два настоящих устройства. Так как у меня нет второго КПК, я решил воспользоваться в качестве второго устройства своим смартфоном под управлением Windows Mobile 2005. Поскольку графический интерфейс программ для смартфонов не поддерживает кнопки, мне пришлось добавить в решение новый проект

IrDA_Smartphone_CS
и частично переписать код программы.

Вместо кнопок использовалось меню, а вместо элемента управления

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

Технология Bluetooth