52628.fb2
Несмотря на растущую популярность Wi-Fi, Bluetooth и других беспроводных технологий, по-прежнему не сдает своих позиций и передача данных через инфракрасный порт. Например, все мы каждый день применяем инфракрасный порт при использовании дистанционного пульта телевизора! Вы можете использовать этот способ работы в своих приложениях для передачи разных типов данных.
Так как в этой технологии для передачи данных используется свет, то необходимо прямое соединение устройств, чтобы между ними не было препятствий. Несмотря на подобное ограничение, соединение через инфракрасный порт по-прежнему широко используется в цифровых камерах, КПК и ноутбуках. В этой главе будет показано, как использовать инфракрасный порт при помощи класса IrDAClient
, входящего в библиотеку классов .NET Compact Framework.
Основанная в 1993 году как некоммерческая организация, Ассоциация инфракрасной передачи данных (Infrared Data Association, или сокращенно IrDA) является международной ассоциацией (www.irda.org), создающей и продвигающей стандарты инфракрасной связи, позволяющие пользователям соединять устройства для передачи данных. Стандарты Infrared Data Association поддерживают огромное число устройств. На данный момент существует несколько версий технологии IrDA, которые различаются скоростью передачи данных.
Протокол IrDA позволяет соединяться с другим устройством без проводов при помощи ИК-излучения. Порт IrDA позволяет устанавливать связь на расстоянии до 1-2 метров. Интерфейс IrDA предполагает малую мощность потребления, что позволяет создавать недорогую продукцию.
Практически все устройства под управлением 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.
Imports System.Net
Imports System.IO
Imports System.Net.Sockets
Для работы с инфракрасной связью необходимо подключить к проекту класс IrDAClient
. Для этого выполним команду меню Project►Add Reference
и в диалоговом окне выберем пункт System.Net.IrDa
.
Теперь нужно объявить переменные на уровне класса, как показано в листинге 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.
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.
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.
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-соединение.
Но и тут не обошлось без ложки дегтя в бочке меда. Во-первых, существует два различных подхода к реализации Bluetooth-соединений, которые не совместимы друг с другом. Во-вторых, пока не существует поддержки этой технологии в управляемом коде .NET Compact Framework. Примеры с Bluetooth-связью мы будем приводить для устройств под управлением Windows Mobile 5.0, так как они гарантированно используют одну и ту же реализацию Bluetooth-технологии. Так как библиотека .NET Compact Framework не имеет в своем составе классов, работающих с Bluetooth, то придется воспользоваться вызовами функций Windows API, как показано в листинге 12.6.
public enum RadioMode {
Off = 0,
Connectable = 1,
Discoverable = 2
}
/// <summary>
/// Получает текущий статус bluetooth
/// </summary>
/// <param name="dwMode">флаги</param>
/// <returns></returns>
[DllImport("BthUtil.dll")]
public static extern int BthGetMode(out RadioMode dwMode);
/// <summary>
/// Устанавливает новый режим bluetooth
/// </summary>
/// <param name="dwMode">флаги для установки режима</param>
/// <returns></returns>
[DllImport("BthUtil.dll")]
public static extern int BthSetMode(RadioMode dwMode);
private void mnuOn_Click(object sender, EventArgs e) {
BthSetMode(RadioMode.Connectable);
lblStatus.Text = RadioMode.Connectable.ToString();
}
private void Form1_Load(object sender, EventArgs e) {
RadioMode mode;
int ret = BthGetMode(out mode);
lblStatus.Text = mode.ToString();
}
private void mnuOff_Click(object sender, EventArgs e) {
ВthSetMode(RadioMode.Off);
lblStatus.Text = RadioMode.Off.ToString();
}
В этом примере после запуска приложения текущий режим Bluetooth определяется при помощи функции BthGetMode
, а с помощью команд меню пользователь может включать или выключать Bluetooth-соединение, используя функцию BthSetMode
.
Несомненно, маленькие мобильные устройства, будь то смартфон или КПК, идеально подходят на роль коммуникационных устройств. В этой главе были приведены только самые простые примеры использования связи между устройствами. В последнее время набирают обороты такие виды связи, как Wi-Fi, GPS и GPRS. Кроме того, мобильные устройства имеют в своем составе браузеры для путешествия по Всемирной паутине. Таким образом, серьезному разработчику необходимо освоить весь спектр технологий, связанных с обменом данными между устройствами.