在 C 与 Bluez

int get_l2cap_connection () {

首先,我们需要的所有变量,将在适当的位置进行解释。

    int ssock = 0;
    int csock = 0;
    int reuse_addr = 1;
    struct sockaddr_l2 src_addr;
    struct bt_security bt_sec;
    int result = 0;

首先,我们需要创建一个套接字,我们可以接受来自的连接。socket 系列是 PF_BLUETOOTH,socket 类型是 SOCK_SEQPACKET(我们想要一个类似 TCP 的套接字,而不是 raw),协议是蓝牙协议 L2CAP(BTPROTO_L2CAP)。

    ssock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);

我们想确保它是成功的:

    if (ssock < 0) {
        perror("Opening L2CAP socket failed");
        return -1;
    }

我们现在必须使用通配符地址填充源地址结构,因此任何具有任何地址的蓝牙设备都可以连接到我们。通配符地址在 bluetooth.h 中定义为 BDADDR_ANY。要将其复制到地址结构中,我们可以使用 bacpy 函数。我们还必须设置地址系列,地址类型和通道 ID。

    memset(&src_addr, 0, sizeof(src_addr));
    bacpy(&src_addr.l2_bdaddr, BDADDR_ANY);
    src_addr.l2_family = AF_BLUETOOTH;
    src_addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
    src_addr.l2_cid = htobs(CID_ATT);

设置 SO_REUSEADDR 选项将允许我们在必要时再次快速调用 bind(这可以省略):

    setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));

接下来,我们必须使用刚刚定义的源地址结构绑定套接字。我们再次检查返回值以确保它有效。

    result = bind(ssock, (struct sockaddr*) &src_addr, sizeof(src_addr));
    if (result < 0) {
        perror("Binding L2CAP socket failed");
        return -1;
    }

接下来是设置安全级别。请注意,此步骤是可选的,但将安全级别设置为 MEDIUM 将允许自动与设备配对(内核处理实际配对)。

    memset(&bt_sec, 0, sizeof(bt_sec));
    bt_sec.level = BT_SECURITY_MEDIUM;
    result = setsockopt(ssock, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, sizeof(bt_sec));
    if (result != 0) {
        perrorno("Setting L2CAP security level failed");
        return -1;
    }

现在我们可以告诉内核我们的 ssock 是一个被动套接字,它将接受一个连接。第二个参数是积压。如果你想了解更多信息,listen 的联机帮助页面包含你需要的所有信息。

    result = listen(ssock, 10);
    if (result < 0) {
        perror("Listening on L2CAP socket failed");
        return -1;
    }

现在我们可以等待传入的连接。一旦 accept 返回,peer_addr 结构将包含所连接设备的地址。csock 将是我们可以读取/写入的套接字的文件描述符,以便与连接的设备进行通信。

    memset(peer_addr, 0, sizeof(*peer_addr));
    socklen_t addrlen = sizeof(*peer_addr);
    csock = accept(ssock, (struct sockaddr*)peer_addr, &addrlen);
    if (csock < 0) {
        perror("Accepting connection on L2CAP socket failed");
        return -1;
    }

我们可以打印连接设备的地址(当然是可选的)。我们可以使用 batostr 函数将蓝牙地址转换为字符串。

    printf("Accepted connection from %s", batostr(&peer_addr->l2_bdaddr));

如果我们不想要任何其他设备连接,我们应该关闭服务器套接字。在与设备通信完成后,使用 csock 执行相同的操作。

    close(ssock);
    return csock;
}