Windows原生蓝牙编程 第三章 配对后进行蓝牙通信【C++】

蓝牙系列文章目录
第一章 获取本地蓝牙并扫描周围蓝牙信息并输出
第二章 选取设备输入配对码并配对
第三章 配对后进行蓝牙通信



前言

接着第二章,我们已经配对完成,接下来就是通过winsock进行通信了。


头文件

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4995)

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <windows.h>
#include <stdlib.h>
#include<bluetoothapis.h>
#include <winsock.h>
#include <ws2bth.h>
#include <locale>
#include <codecvt>
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "bthprops.lib")
#pragma comment(lib,"ws2_32.lib")
using namespace std;
string PassKey;
HANDLE btdi;
vector<BLUETOOTH_DEVICE_INFO> devices;
BLUETOOTH_DEVICE_INFO device;
SOCKET sockClient;
WSADATA wsaData;

我又加了个SOCKET全局变量来保存套接字和WSADATA wsaData用于初始化套接字库。

一、建立连接套接字

bool buildConnect(BLUETOOTH_DEVICE_INFO device, SOCKET& sockClient) {
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		cout << "Winsock库初始化失败" << endl;
		return FALSE;
	}
	SOCKET client_socket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
	if (client_socket == INVALID_SOCKET) {
		cout << "套接字创建失败" << endl;
		WSACleanup();
		return FALSE;
	}

	sockClient = client_socket;
	SOCKADDR_BTH serverAddress;
	memset(&serverAddress, 0, sizeof(serverAddress));
	serverAddress.addressFamily = AF_BTH;
	BTH_ADDR deviceAddress = device.Address.ullLong;
	serverAddress.btAddr = deviceAddress;
	serverAddress.port = 0;
	serverAddress.serviceClassId = SerialPortServiceClass_UUID;

	int err = ::connect(client_socket, (SOCKADDR*)&serverAddress, sizeof(serverAddress));
	if (0 == err) {
	}
	else {
		cout << "connect连接失败" << endl;
		closesocket(client_socket);
		WSACleanup();
		return FALSE;
	}

	while (true) {
		cout << "选择您的操作:1.发送信息 2.退出" << endl;
		int choice;
		cin >> choice;
		if (choice == 1) {
			cout << "请输入您想要发送的信息:";
			string message;
			cin >> message;
			int iCount = 0;
			if (sendMessage(client_socket, message, iCount)) {
				cout << "信息传输成功,发送字符数:" << iCount << endl;
			}
			else {
				cout << "send失败" << endl;
				return false;
			}
		}
		else if (choice == 2) {
			break;
		}
		else {
			cout << "输入错误,请重新输入" << endl;
		}
	}
	closesocket(client_socket);
	WSACleanup();
	BluetoothUpdateDeviceRecord(&device);
	return TRUE;
}

二、设置发送信息函数

bool sendMessage(SOCKET sockClient, string message, int& iCount) {
	int sum = 0;
	while (iCount < message.size())
	{
		wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
		string utf8String = converter.to_bytes(converter.from_bytes(message));
		iCount = send(sockClient, utf8String.data() + sum, utf8String.size() - sum, 0);
		if (iCount == SOCKET_ERROR)
		{
			cout << "发送失败" << endl;
			return false;
		}
		sum += iCount;
	}
}

因为我测试服务端选的utf8格式,所以要把string转为utf8格式再进行传输

string String_To_UTF8(const std::string& str)
{
	int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

	wchar_t* pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
	ZeroMemory(pwBuf, nwLen * 2 + 2);

	::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char* pBuf = new char[nLen + 1];
	ZeroMemory(pBuf, nLen + 1);

	::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr(pBuf);

	delete[]pwBuf;
	delete[]pBuf;

	pwBuf = NULL;
	pBuf = NULL;

	return retStr;
}

三、全部代码

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4995)

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <windows.h>
#include <stdlib.h>
#include<bluetoothapis.h>
#include <winsock.h>
#include <ws2bth.h>
#include<Stringapiset.h>
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "bthprops.lib")
#pragma comment(lib,"ws2_32.lib")
using namespace std;
string PassKey;
HANDLE btdi;
vector<BLUETOOTH_DEVICE_INFO> devices;
BLUETOOTH_DEVICE_INFO device;
SOCKET sockClient;
WSADATA wsaData;

string wstring2string(const wstring& ws)
{
	string curLocale = setlocale(LC_ALL, NULL);
	setlocale(LC_ALL, "chs");
	const wchar_t* _Source = ws.c_str();
	size_t _Dsize = 2 * ws.size() + 1;
	char* _Dest = new char[_Dsize];
	memset(_Dest, 0, _Dsize);
	wcstombs(_Dest, _Source, _Dsize);
	string result = _Dest;
	delete[]_Dest;
	setlocale(LC_ALL, curLocale.c_str());
	return result;
}
string String_To_UTF8(const std::string& str)
{
	int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

	wchar_t* pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
	ZeroMemory(pwBuf, nwLen * 2 + 2);

	::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char* pBuf = new char[nLen + 1];
	ZeroMemory(pBuf, nLen + 1);

	::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr(pBuf);

	delete[]pwBuf;
	delete[]pBuf;

	pwBuf = NULL;
	pBuf = NULL;

	return retStr;
}
string getMAC(BLUETOOTH_ADDRESS Daddress)
{
	/*string addr;
	addr = addr.sprintf("%02x:%02x:%02x:%02x:%02x:%02x", Daddress.rgBytes[5], Daddress.rgBytes[4], Daddress.rgBytes[3], Daddress.rgBytes[2], Daddress.rgBytes[1], Daddress.rgBytes[0]);
	return addr;*/
	ostringstream oss;
	oss << hex << setfill('0') << uppercase;
	for (int i = 5; i >= 0; --i) {
		oss << setw(2) << static_cast<int>(Daddress.rgBytes[i]);
		if (i > 0) {
			oss << ":";
		}
	}
	return oss.str();
}

vector<BLUETOOTH_DEVICE_INFO> scanDevices()
{
	HBLUETOOTH_RADIO_FIND hbf = NULL;
	HANDLE hbr = NULL;
	HBLUETOOTH_DEVICE_FIND hbdf = NULL;
	BLUETOOTH_FIND_RADIO_PARAMS btfrp = { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; //调用BluetoothFindFirstDevice搜索本机蓝牙收发器所需要的搜索参数对象
	BLUETOOTH_RADIO_INFO bri = { sizeof(BLUETOOTH_RADIO_INFO) }; //初始化一个储存蓝牙收发器信息(BLUETOOTH_RADIO_INFO)的对象bri
	BLUETOOTH_DEVICE_SEARCH_PARAMS btsp = { sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS) };//调用BluetoothFindFirstDevice搜索本所需要的搜索参数对象
	BLUETOOTH_DEVICE_INFO btdi = { sizeof(BLUETOOTH_DEVICE_INFO) };  //初始化一个远程蓝牙设备信息(BLUETOOTH_DEVICE_INFO)对象btdi,以储存搜索到的蓝牙设备信息
	hbf = BluetoothFindFirstRadio(&btfrp, &hbr); //得到第一个被枚举的蓝牙收发器的句柄hbf可用于BluetoothFindNextRadio,hbr可用于BluetoothFindFirstDevice。若没有找到本机的蓝牙收发器,则得到的句柄hbf=NULL

	vector<BLUETOOTH_DEVICE_INFO> res;

	bool brfind = hbf != NULL;
	while (brfind)
	{
		if (BluetoothGetRadioInfo(hbr, &bri) == ERROR_SUCCESS)//获取蓝牙收发器的信息,储存在bri中
		{
			cout << "[Local Device Name]:" << wstring2string(bri.szName) << "\t";   //蓝牙收发器的名字
			cout << "[Local Device Address]: " << getMAC(bri.address) << endl;
			cout << "------------------------蓝牙扫描结果如下----------------------------" << endl;

			btsp.hRadio = hbr;  //设置执行搜索设备所在的句柄,应设为执行BluetoothFindFirstRadio函数所得到的句柄
			btsp.fReturnAuthenticated = TRUE;//是否搜索已配对的设备
			btsp.fReturnConnected = FALSE;//是否搜索已连接的设备
			btsp.fReturnRemembered = TRUE;//是否搜索已记忆的设备
			btsp.fReturnUnknown = TRUE;//是否搜索未知设备
			btsp.fIssueInquiry = TRUE;//是否重新搜索,True的时候会执行新的搜索,时间较长,FALSE的时候会直接返回上次的搜索结果。
			btsp.cTimeoutMultiplier = 30;//指示查询超时的值,以1.28秒为增量。 例如,12.8秒的查询的cTimeoutMultiplier值为10.此成员的最大值为48.当使用大于48的值时,调用函数立即失败并返回
			hbdf = BluetoothFindFirstDevice(&btsp, &btdi);//通过找到第一个设备得到的HBLUETOOTH_DEVICE_FIND句柄hbdf来枚举远程蓝牙设备,搜到的第一个远程蓝牙设备的信息储存在btdi对象中。若没有远程蓝牙设备,hdbf=NULL。
			bool bfind = hbdf != NULL;
			int i = 0;

			while (bfind)
			{
				cout << ++i << " " << "[Name]:" << wstring2string(btdi.szName);  //远程蓝牙设备的名字
				cout << "\t[Address]:" << getMAC(btdi.Address) << endl;
				res.push_back(btdi);
				bfind = BluetoothFindNextDevice(hbdf, &btdi);//通过BluetoothFindFirstDevice得到的HBLUETOOTH_DEVICE_FIND句柄来枚举搜索下一个远程蓝牙设备,并将远程蓝牙设备的信息储存在btdi中
			}
			BluetoothFindDeviceClose(hbdf);//使用完后记得关闭HBLUETOOTH_DEVICE_FIND句柄hbdf。
		}
		CloseHandle(hbr);
		brfind = BluetoothFindNextRadio(hbf, &hbr);//通过BluetoothFindFirstRadio得到的HBLUETOOTH_RADIO_FIND句柄hbf来枚举搜索下一个本地蓝牙收发器,得到可用于BluetoothFindFirstDevice的句柄hbr。
	}
	return res;
}

void setPassKey() {
	cout << "请输入配对码:(如果不知道请输入默认0000):";
	cin >> PassKey;
	cout << "您输入的配对码为: " << PassKey << endl;
}

bool pairDevice() {
	cout << "输入你想要配对的设备的序号:";
	int index;
	cin >> index;
	//获取设备信息
	device = devices[index - 1];
	//输入配对码
	setPassKey();
	//string转PWSTR
	wstringstream wss;
	for (char c : PassKey) {
		wss << wchar_t(c);
	}
	wstring wstr = wss.str();
	const wchar_t* wcharPtr = wstr.c_str();
	PWSTR AUTHENTICATION_PASSKEY = const_cast<PWSTR>(wcharPtr);
	//开始配对
	wstring ws = device.szName;
	HBLUETOOTH_AUTHENTICATION_REGISTRATION hCallbackHandle = 0;
	DWORD result = -1;
	if (!device.fAuthenticated) {
		result = BluetoothAuthenticateDevice(NULL, btdi, &device, AUTHENTICATION_PASSKEY, (ULONG)wcslen(AUTHENTICATION_PASSKEY));  //配对函数,AUTHENTICATION_PASSKEY是我的蓝牙配对码
		if (result != ERROR_SUCCESS) {
			switch (result)
			{
			case ERROR_CANCELLED:
				cout << "用户取消了身份验证或配对操作" << endl;
				break;
			case ERROR_INVALID_PARAMETER:
				cout << "传递给函数的参数无效" << endl;
				break;
			case ERROR_NO_MORE_ITEMS:
				cout << "没有更多的设备可以配对" << endl;
				break;
			case ERROR_NOT_SUPPORTED:
				cout << "不支持请求的操作" << endl;
				break;
			case ERROR_GEN_FAILURE:
				cout << "通用失败错误" << endl;
				break;
			case ERROR_BUSY:
				cout << "蓝牙堆栈忙" << endl;
				break;
			case ERROR_TIMEOUT:
				cout << "操作超时" << endl;
				break;
			case ERROR_DEVICE_NOT_CONNECTED:
				cout << "蓝牙设备未连接" << endl;
				break;
			case ERROR_DEVICE_NOT_AVAILABLE:
				cout << "设备不可用" << endl;
				break;
			default:
				cout << "校验码出错,请手动进行设备连接" << endl;
				break;
			}
			return false;
		}
	}
	cout << "身份验证成功,蓝牙设备已成功配对" << endl;;
	BluetoothUpdateDeviceRecord(&device);
	return true;
}

bool sendMessage(SOCKET sockClient, string message, int& iCount) {
	int sum = 0;
	while (iCount < message.size())
	{
		string utf8message = String_To_UTF8(message);
		iCount = send(sockClient, utf8message.data() + sum, utf8message.size() - sum, 0);
		if (iCount == SOCKET_ERROR)
		{
			cout << "发送失败" << endl;
			return false;
		}
		sum += iCount;
	}
}

bool buildConnect(BLUETOOTH_DEVICE_INFO device, SOCKET& sockClient) {
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		cout << "Winsock库初始化失败" << endl;
		return FALSE;
	}
	SOCKET client_socket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
	if (client_socket == INVALID_SOCKET) {
		cout << "套接字创建失败" << endl;
		WSACleanup();
		return FALSE;
	}

	sockClient = client_socket;
	SOCKADDR_BTH serverAddress;
	memset(&serverAddress, 0, sizeof(serverAddress));
	serverAddress.addressFamily = AF_BTH;
	BTH_ADDR deviceAddress = device.Address.ullLong;
	serverAddress.btAddr = deviceAddress;
	serverAddress.port = 0;
	serverAddress.serviceClassId = SerialPortServiceClass_UUID;

	int err = ::connect(client_socket, (SOCKADDR*)&serverAddress, sizeof(serverAddress));
	if (0 == err) {
	}
	else {
		cout << "connect连接失败" << endl;
		closesocket(client_socket);
		WSACleanup();
		return FALSE;
	}

	while (true) {
		cout << "选择您的操作:1.发送信息 2.退出" << endl;
		int choice;
		cin >> choice;
		if (choice == 1) {
			cout << "请输入您想要发送的信息:";
			string message;
			cin >> message;
			int iCount = 0;
			if (sendMessage(client_socket, message, iCount)) {
				cout << "信息传输成功,发送字符数:" << iCount << endl;
			}
			else {
				cout << "send失败" << endl;
				return false;
			}
		}
		else if (choice == 2) {
			break;
		}
		else {
			cout << "输入错误,请重新输入" << endl;
		}
	}
	closesocket(client_socket);
	WSACleanup();
	BluetoothUpdateDeviceRecord(&device);
	return TRUE;
}

void main() {
	devices = scanDevices();
	if (pairDevice()) {
		buildConnect(device, sockClient);
	}
	return;
}

四、测试服务端选择及蓝牙通信

随便在网上下载了个蓝牙测试的app
在这里插入图片描述
测试一下,选择要连接的设备并且输入配对码
在这里插入图片描述
连接成功的同时手机显示连接成功
在这里插入图片描述
发送两条信息
在这里插入图片描述

同时手机收到
在这里插入图片描述
返回发送字符数那有点问题,因为转成utf-8格式,一个中文占3个字符,我懒得改了,不过测试结果还是很成功的,完美实现蓝牙通信。

总结

如果您觉得有用的话,务必点赞评论收藏一波,万分感谢咯!=v=

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
1 Introduction ......................................................................................... 4<br>1.1 Bluetooth Protocol Stack............................................................. 4<br>2 Protocols in Bluetooth Architecture.................................................. 6<br>2.1 Bluetooth Core Protocols ............................................................ 7<br>2.1.1 Baseband ....................................................................... 7<br>2.1.1.1 Audio................................................................ 7<br>2.1.2 Link Manager Protocol ................................................... 7<br>2.1.3 Logical Link Control and Adaptation Protocol................. 7<br>2.1.4 Service Discovery Protocol (SDP).................................. 8<br>2.2 Cable Replacement Protocol ...................................................... 8<br>2.2.1 RFCOMM....................................................................... 8<br>2.3 Telephony Control Protocol......................................................... 8<br>2.3.1 Telephony Control – Binary............................................ 8<br>2.3.2 Telephony Control – AT Commands .............................. 8<br>2.4 Adopted Protocols....................................................................... 9<br>2.4.1 PPP................................................................................ 9<br>2.4.2 TCP/UDP/IP ................................................................... 9<br>2.4.3 OBEX Protocol ............................................................... 9<br>2.4.3.1 Content Formats .............................................. 9<br>2.4.4 WAP............................................................................. 10<br>2.4.4.1 Content Formats ............................................ 11<br>3 Bluetooth Usage Models and Protocols ......................................... 12<br>3.1 File Transfer.............................................................................. 12<br>3.2 Internet Bridge .......................................................................... 12<br>3.3 LAN Access .............................................................................. 13<br>3.4 Synchronization ........................................................................ 14<br>3.5 Three-in-One Phone ................................................................. 14<br>3.6 Ultimate Headset ...................................................................... 15<br>4 Summary............................................................................................ 16<br>5 References......................................................................................... 17<br>6 Acronyms........................................................................................... 19
### 回答1: Windows USB编程中有很多第三方库可供选择。这些库可以帮助开发者更便捷地与USB设备进行通信和控制。以下是一些常见的Windows USB编程第三方库: 1. libusb:这是一个跨平台的USB访问库,可以在Windows、Linux和macOS上使用。它提供了一套简单的API,使开发者可以直接与USB设备进行通信,包括读写数据、枚举设备和控制设备等。 2. WinUSB:这是一个微软开发的库,专门用于在Windows平台上进行USB通信。它提供了一套基于WinUSB驱动程序的API,使开发者可以很容易地进行设备枚举、数据传输和设备控制等操作。 3. USBIO:这是一个商业化的USB编程库,也可以在Windows上使用。它提供了丰富的API,支持设备的读写、枚举和配置等操作。此外,USBIO还提供了一些高级功能,如IOCTL控制、USB传输日志和错误记录等。 4. libusb-win32:这是一个基于libusb的Windows开发驱动程序,可以通过WinUSB和libusb之间的转换层来访问设备。它提供了与libusb相似的API,但只适用于Windows平台。 这些第三方库都具有各自的特点和优势,开发者可以根据自己的需求选择适合自己的库进行USB编程。无论是使用哪个库,都可以更方便地进行USB设备的通信和控制,并加快开发过程。 ### 回答2: Windows USB编程第三方库指的是针对Windows操作系统的USB设备编程所使用的外部库。Windows提供了一套开发接口(API)用于处理USB设备的通信和操作,但是使用这些原生API需要开发者具备较高的底层知识和经验。为了简化USB设备编程的复杂性,提高开发效率,许多第三方库应运而生。 这些第三方库提供了一套高级接口和封装,使得开发者可以更加方便地进行USB设备的读写、控制和通信。通过调用这些库提供的函数,可以实现多种USB设备的操作,例如连接、断开、发送和接收数据等。 常见的Windows USB编程第三方库包括libusb、WinUSB、USBHUB等。这些库提供了跨平台支持,可以在不同版本的Windows操作系统上运行,并且支持各种USB设备类型,包括鼠标、键盘、打印机、摄像头等。 使用第三方库进行USB编程可以带来以下优点: 1. 简化开发流程:第三方库提供了高级封装,屏蔽了底层细节,使得开发者可以更加专注于业务逻辑的实现。 2. 提高开发效率:使用库提供的函数和接口,开发者可以更快速地完成USB设备的接入和操作。 3. 支持跨平台:第三方库通常支持跨多个操作系统,提供了一致的接口,便于在不同平台上进行开发和测试。 需要注意的是,选择合适的第三方库应该考虑其稳定性、功能性和社区支持等因素,以确保在开发过程中能够得到足够的技术支持和维护。 ### 回答3: Windows USB编程的第三方库是一种用于在Windows操作系统上进行USB设备通信的软件工具。它提供了一组函数和类,使开发人员可以方便地与USB设备进行通信和控制。 通过使用这些第三方库,开发人员可以避免直接使用Windows API进行USB编程的复杂性,减少了开发的工作量并提高了代码的可读性和可维护性。 这些库通常提供以下功能: 1. 设备枚举:通过这些函数和类,开发人员可以列举系统中所有连接到计算机上的USB设备,并获取设备的信息,如设备的供应商ID和产品ID。 2. 设备打开和关闭:开发人员可以使用这些函数和类打开和关闭特定的USB设备,以便进行通信和控制。 3. 读写数据:这些库还提供了读取和写入数据的函数和类,使开发人员可以向设备发送命令和接收设备的响应。 4. 控制传输:开发人员可以通过使用这些函数和类发送控制传输请求来与设备进行通信,并对设备进行配置和管理。 使用第三方库进行Windows USB编程可以提高开发效率,并且可以在开发过程中避免一些常见的错误和问题。此外,这些库通常提供了丰富的文档和示例代码,以帮助开发人员更好地理解和使用库的功能。 总之,Windows USB编程的第三方库是对Windows操作系统的USB编程接口进行封装和简化的软件工具,可以帮助开发人员更轻松地与USB设备进行通信和控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AAA码农宝哥.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值