我正在尝试在我的 Linux 笔记本电脑和 Android 手机之间创建一个简单且自定义的蓝牙连接。在 Linux 方面,我使用 BlueZ libbluetooth 库来设置服务器。它的代码与我在 github 上看到的其他代码非常相似:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/rfcomm.h>
sdp_session_t *register_service();
int main(int argc, char **argv)
{
struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
char str[1024] = { 0 };
int s, client, bytes_read;
sdp_session_t *session;
socklen_t opt = sizeof(rem_addr);
session = register_service();
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t) 11;
printf("Trying to bind...");
fflush(stdout);
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
printf("bound\n");
fflush(stdout);
printf("Waiting for connection...");
fflush(stdout);
listen(s, 1);
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
ba2str( &rem_addr.rc_bdaddr, buf );
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
sprintf(str,"to Android.");
printf("sent [%s]\n",str);
write(client, str, sizeof(str));
close(client);
close(s);
sdp_close( session );
return 0;
}
sdp_session_t *register_service()
{
uint32_t svc_uuid_int[] = { 0x00000000,0x00000000,0x00000000,0x3233 };
uint8_t rfcomm_channel = 11;
const char *service_name = "Remote Host";
const char *service_dsc = "What the remote should be connecting to.";
const char *service_prov = "Your mother";
uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid;
sdp_list_t *l2cap_list = 0,
*rfcomm_list = 0,
*root_list = 0,
*proto_list = 0,
*access_proto_list = 0;
sdp_data_t *channel = 0, *psm = 0;
sdp_record_t *record = sdp_record_alloc();
// set the general service ID
sdp_uuid128_create( &svc_uuid, &svc_uuid_int );
sdp_set_service_id( record, svc_uuid );
sdp_list_t service_class = {NULL, &svc_uuid};
sdp_set_service_classes( record, &service_class);
// make the service record publicly browsable
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
root_list = sdp_list_append(0, &root_uuid);
sdp_set_browse_groups( record, root_list );
// set l2cap information
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
l2cap_list = sdp_list_append( 0, &l2cap_uuid );
proto_list = sdp_list_append( 0, l2cap_list );
// set rfcomm information
sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );
sdp_list_append( rfcomm_list, channel );
sdp_list_append( proto_list, rfcomm_list );
// attach protocol information to service record
access_proto_list = sdp_list_append( 0, proto_list );
sdp_set_access_protos( record, access_proto_list );
// set the name, provider, and description
sdp_set_info_attr(record, service_name, service_prov, service_dsc);
int err = 0;
sdp_session_t *session = 0;
// connect to the local SDP server, register the service record, and
// disconnect
session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY );
err = sdp_record_register(session, record, 0);
// cleanup
//sdp_data_free( channel );
sdp_list_free( l2cap_list, 0 );
sdp_list_free( rfcomm_list, 0 );
sdp_list_free( root_list, 0 );
sdp_list_free( access_proto_list, 0 );
return session;
}
我能够在 Linux 中运行服务器端代码而不会出错:
$ ./bluetooth-server
Trying to bind...bound
Waiting for connection...
然后我可以sdptool
用来查看我的 RFCOMM 套接字和服务(描述、通道号和所有其他信息看起来都正确):
Service Name: Remote Host
Service Description: What the remote should be connecting to.
Service Provider: Your mother
Service RecHandle: 0x10009
Service Class ID List:
UUID 128: 00000000-0000-0000-0000-000033320000
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 11
现在,在 Android 方面,我首先通过标准设置屏幕将手机与 Linux 服务器配对。配对后,我会使用 Android 端的代码来扫描蓝牙设备,如果它是我的 Linux 设备,那么我会尝试连接到它。我尝试了人们在堆栈溢出时建议的两种不同方法来建立连接:
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(device.getName().equals("ubuntu-0")) {
try {
mBluetoothAdapter.cancelDiscovery();
// This returns the value 00001103-0000-1000-8000-00805f9b34fb
UUID uuid = device.getUuids()[0].getUuid();
// This does not work
//BluetoothSocket tmp = device.createRfcommSocketToServiceRecord(uuid);
// And neither does this
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
BluetoothSocket tmp = (BluetoothSocket) m.invoke(device, 11); // Match channel 11
tmp.connect(); // Exception is thrown here
}
catch(Exception e) {
Log.e("BT", "Could not create RFCOMM socket " + e.toString());
}
}
}
tmp.connect()
当我实际尝试调用时,我不断收到以下异常:
03-20 14:20:13.089: E/BT(16915): Could not create RFCOMM socket
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
有没有人看到我在这里尝试创建连接时做错了什么?请注意,当我调用时,我确实得到了一个返回的 UUID UUID uuid = device.getUuids()[0].getUuid();
...这让我相信配对是好的,它返回 value 00001103-0000-1000-8000-00805f9b34fb
。