Опубликован: 11.01.2013 | Доступ: свободный | Студентов: 623 / 124 | Длительность: 12:06:00
Лекция 9:

Лабораторный практикум по технологиям Bluetooth и Wi-Fi

< Лекция 8 || Лекция 9: 12345

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

Лабораторная работа №3 посвящена самому главному, для чего используется Bluetooth – беспроводной передаче данных. В предыдущих лабораторных работах было описано все необходимое, что нужно сделать до того, как открыть соединение – как найти сервис, к которому мы хотим подключиться, и узнать о нем все, что для этого нужно, а также как сделать так, чтобы клиент смог найти этот сервис.

Теперь можно приступать к созданию соединения и обмену данными. В Bluetooth стеке Microsoft это реализовано с помощью привычного интерфейса Windows Sockets.

Постановка задачи

Написать две программы: клиент и сервер. Клиент подключается к серверу через Bluetooth. После соединения, если в окне клиента ввести какую-то строку, она должна быть передана серверу и выведена в его окне. Если была набрана команда "quit", соединение завершается.

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

Методические рекомендации

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

Делается все это с помощью знакомых вам из курса ОС сокетных функций.

Сервер: создание сервиса

В начале своей работы сервер должен создать сокет, который будет идентифицировать его конец соединения. Делается это с помощью функции socket() с параметрами, специфичными для Bluetooth.

SOCKET s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);

	if (s == -1)
	{
	    // Ошибка
	}

Чтобы клиент мог подключиться к сокету, ему должен быть выделен порт. Сделать это можно при помощи функции bind().

int bind(SOCKET                 s,
         const struct sockaddr* name,
         int                    namelen);

Данной функции нужно передать только что созданный сокет и сокетный адрес, к которому он должен быть привязан. Для Bluetooth он описывается структурой SOCKADDR_BTH (см. лабораторную работу №2). В ней опять нужно заполнить всего два поля: addressFamily и port. Чтобы номер порта был выделен автоматически, их значения остаются прежними. Параметр namelen должен быть равен размеру SOCKADDR_BTH.

В лабораторной работе №2 создавался сервис, к которому никто не мог никто подключиться, т.к. к нему не был привязан ни один сокет. Для того чтобы к нашему сервису мог кто-то подключиться, при его создании в поле lpqsRegInfo-> lpcsaBuffer->LocalAddr->lpSockaddr должен находиться реальный адрес созданного сокета. Получить его можно при помощи функции getsockname().

int getsockname(SOCKET           s,
                struct sockaddr* name,
                int*             namelen);

В качестве параметра s должен быть передан созданный сокет, а в качестве name – указатель на структуру SOCKADDR_BTH, которая получит реальный адрес сокета. Можно передать указатель на ту же переменную, которая использовалась в bind().

Теперь при создании сервиса полю lpcsaBuffer->LocalAddr->lpSockaddr нужно присвоить указатель на реальный сокетный адрес.

Сервер: Ожидание запроса на установление соединения

После того, как сервис создан, можно начинать ждать запрос клиента на установление соединения. Делается это с помощью знакомой функции listen(), в которую передается сокет сервера и 1 в качестве параметра backlog. После вызова этой функции поток переводится в состояние ожидания до прихода запроса на установление соединения.

Клиент: Открытие соединения

Для подключения к серверу необходимо знать его сокетный адрес, где будет прописан адрес Bluetooth-устройства и номер порта, на котором находится сервис. Получить его можно в результате поиска сервисов (он будет находиться в поле lpcsaBuffer->RemoteAddr.lpSockaddr).

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

int connect(SOCKET                 s,
            const struct sockaddr* name,
            int                    namelen);
Параметр namelen должен быть равен размеру SOCKADDR_BTH.

Если подключение удалось, connect() вернет 0.

Сервер: Открытие соединения

При поступлении от клиента запроса на установление соединения listen() должна завершиться, после чего можно открывать соединение, вызвав accept() с теми же параметрами, с которыми вызывалась listen(). При успешном открытии соединения accept() должна вернуть сокет клиента, который будет использоваться далее для управления соединением.

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

Передача данных осуществляется с помощью стандартных сокетных функций send() и recv().

int send(SOCKET          s,
         const char FAR* buf,
         int             len,
         int             flags);
int recv(SOCKET          s,
         char FAR*       buf,
         int             len,
         int             flags);

В качестве параметра s клиент должен передавать свой сокет, а сервер – сокет клиента, который он получил от accept(). buf – это указатель на буфер, в котором содержатся данные или куда они должны попасть, len – его размер. Последний параметр должен быть равен 0.

Если не было никаких ошибок, recv() вернет количество принятых байт или 0, если соединение было завершено. send() должна вернуть количество действительно переданных байт. В случае ошибки, они вернут SOCKET_ERROR.

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

Вызовы send() и recv() должны быть синхронизированы, каждому send() с одной стороны должен соответствовать recv() с другой.

Закрытие соединения

Соединение закрывается путем вызова функции closesocket(), в которую клиент должен передать свой сокет, а сервер – сокет клиента, который он получил от accept()

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

< Лекция 8 || Лекция 9: 12345